需要另外安裝 NUnit Project Template

在 單元測試的藝術 一書中,使用的是 NUnit 與 NSubstitute,但 .NET Core SDK 預設只提供 MSTest 與 xUnit,該如何在 .NET Core 使用我們熟悉的 NUnit 與 NSubstitute 呢 ?

Version


macOS High Sierra 10.13.4
.NET Core 2.1
NUnit 3.10.1
NSubstitute 3.1.0
Rider 2018.1.3

Symptons


1
$ dotnet new -l
  • -l : list ,使用 dotnet new 加上 -l 參數,將列出目前系統所安裝的所有 project template。

nunit000

.NET Core SDK 預設只提供 MSTest 與 xUnit 的 project template。

nunit001

  • 因為 .NET Core SDK 只有 MSTest 與 XUnit,因此 Rider 也只支援 MSTest 與 xUnit

NUnit


nunit002

事實上在 .NET Core 官網的 Available templates for dotnet new,還準備了不少其他 project template 可供下載,其中也包含了 NUnit。

1
$ dotnet new -i "NUnit3.DotNetNew.Template::*"

nunit003

nunit004

  1. 安裝完就會出現 NUnit 3 project template

nunit005

  1. 安裝完後,Rider 也會出現 NUnit 3 Test Project

Project Reference


將 Class Library 的 project reference 加到 Unit Test 專案。

nunit007

  1. 選擇 Unit Test 專案
  2. 按滑鼠右鍵選擇 Add
  3. 選擇 Add Reference

nunit008

  1. 選擇 ClassLib
  2. 按 OK 繼續

NSubstitute


除了 NUnit 外,單元測試另外一個要角就是 NSubstitute,這要另外安裝。

nunit009

  1. 選擇 Unit Test 專案
  2. 按滑鼠右鍵選擇 Manage NuGet Packages

nunit006

  1. 在 NuGet 下輸入 NSubstitute
  2. 選擇 NSubstitute
  3. 在 Unit Test 專案下安裝 NSubstitute

Parallel Test


NUnit 預設並不是以 parallel 進行單元測試,而是以 sequential 方式,也就是 一個單元測試執行完,才會進行下一個單元測試,而不是每個單元測試平行執行。

這種方式雖然安全,但有幾個缺點:

  1. 執行速度較慢,沒有完全發揮多核心 CPU 的優勢
  2. Jenkins 會以 parallel 方式執行單元測試,因此每個單元測試之間不能相依,讓本機與 Jenkins 環境相同

AssemblyInfo.cs

1
2
3
using NUnit.Framework;

[assembly:Parallelizable(ParallelScope.All)]

在 Unit Test 專案下新增 AssemblyInfo.cs,對整個 Unit Test assembly 增加 NUnit 的 Parallelizable attribute,如此每個 test method 都會以 parallel 方式執行單元測試。

nunit010

Conclusion


  • .NET Core SDK 預設沒有支援 NUnit,但只要自行透過 dotnet new -i,即可安裝 NUnit project template
  • NSubstitute 以 NuGet package 形式存在,必須另外安裝
  • NUnit 預設以 sequential 方式執行 Unit Test,不僅沒發揮多核心 CPU 威力,也與 Jenkins 執行環境不同,建議在 Unit Test 專案增加 AssemblyInfo.cs,對整個 Unit Test assembly 增加 Parallelizable(ParallelScope.All) attribute,如此才會以 parallel 方式執行單元測試,也能提早發現 test method 彼此相依可能造成的問題

Sample Code


完整的範例可以在我的 GitHub 上找到

▲