C# NUnit
最后修改于 2023 年 7 月 5 日
C# NUnit 教程展示了如何使用 NUnit 框架在 C# 中进行单元测试。
单元测试是一种软件测试,它测试软件的各个单元(组件)。 单元测试的目的是验证软件的每个单元是否按设计运行。 单元是任何软件中最小的可测试部分。
NUnit 是所有 .NET 语言的单元测试库。 它的灵感来自 Java 的 JUnit。 其他单元测试库包括 XUnit 和 MSTest。
可以将测试放在同一项目目录中或不同的目录中。 我们从一个更简单的选项开始,将测试放在同一项目目录中。 最后,我们将展示后一种选择。
$ dotnet add Microsoft.NET.Test.Sdk $ dotnet new nunit $ dotnet add NUnit3TestAdapter
为了使用 NUnit,我们需要添加这三个库。
C# NUNit 简单示例
我们从一个简单的示例开始。
namespace Arithmetic;
class Basic
{
public static Func<int, int, int> add = (a, b) => a + b;
public static Func<int, int, int> mul = (a, b) => a * b;
public static Func<int, int, int> sub = (a, b) => a - b;
public static Func<int, int, int> div = (a, b) => a / b;
}
我们测试简单的算术函数。
我们将测试放入 tests 目录中。 NUnit 会自动发现我们的测试。
namespace Testing;
using NUnit.Framework;
using Arithmetic;
class ArithTest
{
[Test]
public void SimpleArithmetic()
{
int r1 = Basic.add(3, 3);
Assert.AreEqual(r1, 6);
int r2 = Basic.sub(3, 3);
Assert.AreEqual(r2, 0);
int r3 = Basic.mul(3, 3);
Assert.AreEqual(r3, 9);
int r4 = Basic.div(3, 3);
Assert.AreEqual(r4, 1);
}
}
测试方法使用 [Test] 属性进行注释。 我们使用断言来确保正确的输出。
$ dotnet test ... Starting test execution, please wait... A total of 1 test files matched the specified pattern. Passed! - Failed: 0, Passed: 1, Skipped: 0, Total: 1, ...
C# NUnit 跳过测试
可以使用 [Ignore] 属性跳过测试方法。
namespace Testing;
using NUnit.Framework;
using Arithmetic;
class ArithTest
{
[Test]
public void AddSub()
{
int r1 = Basic.add(3, 3);
Assert.AreEqual(r1, 6);
int r2 = Basic.sub(3, 3);
Assert.AreEqual(r2, 0);
}
[Test]
[Ignore("Ignoring")]
public void MulDiv()
{
int r3 = Basic.mul(3, 3);
Assert.AreEqual(r3, 9);
int r4 = Basic.div(3, 3);
Assert.AreEqual(r4, 1);
}
}
我们有两个测试方法。 其中一个使用 [Ignore] 属性跳过。
C# NUnit TestCase
使用 TestCase 属性,我们可以拥有参数化的测试方法。
namespace Testing;
using NUnit.Framework;
using Arithmetic;
class ArithTest
{
[TestCase(1, 2, 3)]
[TestCase(2, 2, 4)]
[TestCase(-1, 4, 3)]
public void Add(int x, int y, int z)
{
int r = Basic.add(x, y);
Assert.AreEqual(r, z);
}
[TestCase(1, 2, -1)]
[TestCase(2, 2, 0)]
[TestCase(3, 2, 1)]
public void Sub(int x, int y, int z)
{
int r = Basic.sub(x, y);
Assert.AreEqual(r, z);
}
[TestCase(9, 3, 27)]
[TestCase(3, 3, 9)]
[TestCase(-3, -3, 9)]
public void Mul(int x, int y, int z)
{
int r = Basic.mul(x, y);
Assert.AreEqual(r, z);
}
[TestCase(9, 3, 3)]
[TestCase(3, 3, 1)]
[TestCase(8, 2, 4)]
public void Div(int x, int y, int z)
{
int r = Basic.div(x, y);
Assert.AreEqual(r, z);
}
}
在此示例中,我们使用三组值测试每个方法。
C# NUnit TestCaseSource
[TestCaseSource] 属性允许我们从不同的来源读取参数化测试方法的数据。
namespace Testing;
using NUnit.Framework;
using Arithmetic;
public class ArithTest
{
[TestCaseSource(nameof(AddCases))]
public void Add(int x, int y, int z)
{
int r = Basic.add(x, y);
Assert.AreEqual(r, z);
}
[TestCaseSource(nameof(SubCases))]
public void Sub(int x, int y, int z)
{
int r = Basic.sub(x, y);
Assert.AreEqual(r, z);
}
[TestCaseSource(nameof(MulCases))]
public void Mul(int x, int y, int z)
{
int r = Basic.mul(x, y);
Assert.AreEqual(r, z);
}
[TestCaseSource(nameof(DivCases))]
public void Div(int x, int y, int z)
{
int r = Basic.div(x, y);
Assert.AreEqual(r, z);
}
static object[] AddCases =
{
new object[] { 1, 2, 3 },
new object[] { 2, 2, 4 },
new object[] { -1, 4, 3 }
};
static object[] SubCases =
{
new object[] { 1, 2, -1 },
new object[] { 2, 2, 0 },
new object[] { 3, 2, 1 }
};
static object[] MulCases =
{
new object[] { 9, 3, 27 },
new object[] { 3, 3, 9 },
new object[] { -3, -3, 9 }
};
static object[] DivCases =
{
new object[] { 9, 3, 3 },
new object[] { 3, 3, 1 },
new object[] { 8, 2, 4 }
};
}
在此示例中,值放置在数组中。
C# NUnit ExpectedResult
使用 ExpectedResult,我们可以简化测试设置。
namespace Testing;
using NUnit.Framework;
using Arithmetic;
class ArithTest
{
[TestCase(1, 2, ExpectedResult = 3)]
[TestCase(2, 2, ExpectedResult = 4)]
[TestCase(-1, 4, ExpectedResult = 3)]
public int Add(int x, int y)
{
return Basic.add(x, y);
}
[TestCase(1, 2, ExpectedResult = -1)]
[TestCase(2, 2, ExpectedResult = 0)]
[TestCase(3, 2, ExpectedResult = 1)]
public int Sub(int x, int y)
{
return Basic.sub(x, y);
}
[TestCase(9, 3, ExpectedResult = 27)]
[TestCase(3, 3, ExpectedResult = 9)]
[TestCase(-3, -3, ExpectedResult = 9)]
public int Mul(int x, int y)
{
return Basic.mul(x, y);
}
[TestCase(9, 3, ExpectedResult = 3)]
[TestCase(3, 3, ExpectedResult = 1)]
[TestCase(8, 2, ExpectedResult = 4)]
public int Div(int x, int y)
{
return Basic.div(x, y);
}
}
使用 ExpectedResult,我们的代码会稍微缩短一些。
将测试放在单独的目录中
在下面的示例中,我们将展示如何将测试放在单独的目录中。
$ mkdir Separate $ cd Separate
我们创建一个新目录。
$ dotnet new sln
我们创建一个新的空解决方案。
$ mkdir PalindromeService PalindromeService.Tests
创建了两个目录。
$ cd PalindromeService $ dotnet new classlib
我们创建一个新的库。
namespace Palindrome.Services;
using System.Globalization;
public class PalindromeService
{
public bool IsPalindrome(string word)
{
IEnumerable<string> GraphemeClusters(string s)
{
var enumerator = StringInfo.GetTextElementEnumerator(s);
while (enumerator.MoveNext())
{
yield return (string)enumerator.Current;
}
}
var reversed = string.Join("", GraphemeClusters(word).Reverse().ToArray());
return reversed == word;
}
}
PalindromeService 包含 IsPalindrome 方法,该方法确定单词是否为回文。
$ cd .. $ dotnet sln add PalindromeService\PalindromeService.csproj
我们将 PalindromeService 添加到解决方案。
$ cd PalindromeService.Tests $ dotnet add nunit $ dotnet add reference ..\PalindromeService\PalindromeService.csproj
我们转到 PalindromeService.Tests 目录并添加 unit 库,并添加对 PalindromeService 的引用。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="nunit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="coverlet.collector" Version="3.1.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PalindromeService\PalindromeService.csproj" />
</ItemGroup>
</Project>
这就是项目文件的外观。
namespace Palindrome.Services.Tests;
using NUnit.Framework;
public class Tests
{
private PalindromeService? _palindromeService;
[SetUp]
public void SetUp()
{
_palindromeService = new PalindromeService();
}
[TestCase("racecar")]
[TestCase("nun")]
[TestCase("level")]
public void IsPalindrome(string word)
{
var r = _palindromeService!.IsPalindrome(word);
Assert.AreEqual(r, true);
}
}
我们用三个单词测试 IsPalindrome 方法。
[SetUp]
public void SetUp()
{
_palindromeService = new PalindromeService();
}
[Setup] 属性用于提供一组通用函数,这些函数在每次调用测试方法之前执行。 在我们的例子中,我们创建了 PalindromeService。
$ cd .. $ dotnet sln add PalindromeService.Tests\PalindromeService.Tests.csproj
我们将测试项目添加到解决方案。
$ dotnet test
最后,我们可以运行测试。
来源
使用 NUnit 和 .NET Core 进行 C# 单元测试
在本文中,我们使用 NUnit 库在 C# 中完成了单元测试。
作者
列出所有 C# 教程。