在本文中,我们将演示使用 xUnit 和 .NET core(包括 .NET 5 ),向您展示如何编写和运行第一组单元测试。
注意:示例 的路径和生成的模板可能因您而异,具体取决于您使用的版本。
.Net core 或者当前的 .Net5 已经支持主流的三大操作系统 windows, linux, macOS 在 https://dotnet.microsoft.com/download这边我们可以下载到这个Sdk. 在安装后成之后我们可以在 CMD, PowerShell, Bash, 输入
dotnet --version
5.0.102
如果有安装成功的话,我们可以看到 5.0.102。
从命令行中,为您的测试项目创建一个文件夹,更改为它,然后使用:dotnet new
PS D:\malema.net\Exampels> mkdir MyFirstUnitTests
PS D:\malema.net\Exampels> cd MyFristUnitTests
PS D:\malema.net\Exampels\MyFirstUnitTests> dotnet new xunit
Getting ready...
The template "xUnit Test Project" was created successfully.
Processing post-creation actions...
Running 'dotnet restore' on D:\malema.net\Exampels\MyFirstUnitTests\MyFirstUnitTests.csproj...
正在确定要还原的项目…
已还原 D:\malema.net\Exampels\MyFirstUnitTests\MyFirstUnitTests.csproj (用时 647 ms)。
Restore succeeded.
如果查看生成的项目文件,则应看到类似内容:MyFirstUnitTests.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.3.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
</Project>
让我们快速查看此项目文件中的内容:
同时还有一个空单元测试:UnitTest1.cs
using System;
using Xunit;
namespace MyFirstUnitTests
{
public class UnitTest1
{
[Fact]
public void Test1()
{
}
}
}
现在让我们验证一下是不是能正常工作:
PS D:\malema.net\Exampels\MyFirstUnitTests> dotnet pack
用于 .NET 的 Microsoft (R) 生成引擎版本 16.9.0+57a23d249
版权所有(C) Microsoft Corporation。保留所有权利。
正在确定要还原的项目…
所有项目均是最新的,无法还原。
PS D:\malema.net\Exampels\MyFirstUnitTests> dotnet test
正在确定要还原的项目…
所有项目均是最新的,无法还原。
MyFirstUnitTests -> D:\malema.net\Exampels\MyFirstUnitTests\bin\Debug\net5.0\MyFirstUnitTests.dll
D:\malema.net\Exampels\MyFirstUnitTests\bin\Debug\net5.0\MyFirstUnitTests.dll (.NETCoreApp,Version=v5.0)的测试运行
Microsoft (R) 测试执行命令行工具版本 16.9.1
版权所有 (C) Microsoft Corporation。保留所有权利。
正在启动测试执行,请稍候...
总共 1 个测试文件与指定模式相匹配。
已通过! - 失败: 0,通过: 1,已跳过: 0,总计: 1,持续时间: 1 ms - MyFirstUnitTests.dll (net5.0)
(上面这行会是绿色的)
很好! 让我们来写一个真正的单元测试
使用您最喜欢的文本编辑器(推荐用VisualStudio),打开文件UnitTest1.cs 并添加几个测试:
using System;
using Xunit;
namespace MyFirstUnitTests
{
public class UnitTest1
{
[Fact]
public void Add_Should_Return_Total()
{
Assert.Equal(4, Add(2, 2));
}
[Fact]
public void FailingTest()
{
Assert.Equal(5, Add(2, 2));
}
//我们要测试的方法正常在其它的项目下面,在这边只是演示方便
int Add(int x, int y)
{
return x + y;
}
}
}
让我们再跑一下测试,看一下会发生什么事情
PS D:\malema.net\Exampels\MyFirstUnitTests> dotnet test
正在确定要还原的项目…
所有项目均是最新的,无法还原。
MyFirstUnitTests -> D:\malema.net\Exampels\MyFirstUnitTests\bin\Debug\net5.0\MyFirstUnitTests.dll
D:\malema.net\Exampels\MyFirstUnitTests\bin\Debug\net5.0\MyFirstUnitTests.dll (.NETCoreApp,Version=v5.0)的测试运行
Microsoft (R) 测试执行命令行工具版本 16.9.1
版权所有 (C) Microsoft Corporation。保留所有权利。
正在启动测试执行,请稍候...
总共 1 个测试文件与指定模式相匹配。
[xUnit.net 00:00:00.41] MyFirstUnitTests.UnitTest1.FailingTest [FAIL]
失败 MyFirstUnitTests.UnitTest1.FailingTest [7 ms]
错误消息:
Assert.Equal() Failure
Expected: 5
Actual: 4
堆栈跟踪:
at MyFirstUnitTests.UnitTest1.FailingTest() in D:\malema.net\Exampels\MyFirstUnitTests\UnitTest1.cs:line 17
失败! - 失败: 1,通过: 1,已跳过: 0,总计: 2,持续时间: 11 ms - MyFirstUnitTests.dll (net5.0)
我们可以看到有一个出错了。(我们故意写错了)
现在我们已经运行了您的第一个单元测试,让我们介绍另一种编写测试的方法:使用Theory。
一个很好的例子是测试数字算法。 假设您想测试一个确定数字是否为奇数的算法。 如果您正在编写正面测试(奇数),那么如果一个数是偶数则会导致它失败,而不是因为测试或算法错误。
代码如下
using Xunit;
namespace MyFirstUnitTests
{
public class UnitTest1
{
[Theory]
[InlineData(3)]
[InlineData(5)]
[InlineData(6)]
public void MyFirstTheory(int value)
{
Assert.True(IsOdd(value));
}
//我们要测试的方法正常在其它的项目下面,在这边只是演示方便
bool IsOdd(int value)
{
return value % 2 == 1;
}
}
}
再跑一下测试
PS D:\malema.net\Exampels\MyFirstUnitTests> dotnet test
正在确定要还原的项目…
所有项目均是最新的,无法还原。
MyFirstUnitTests -> D:\malema.net\Exampels\MyFirstUnitTests\bin\Debug\net5.0\MyFirstUnitTests.dll
D:\malema.net\Exampels\MyFirstUnitTests\bin\Debug\net5.0\MyFirstUnitTests.dll (.NETCoreApp,Version=v5.0)的测试运行
Microsoft (R) 测试执行命令行工具版本 16.9.1
版权所有 (C) Microsoft Corporation。保留所有权利。
正在启动测试执行,请稍候...
总共 1 个测试文件与指定模式相匹配。
[xUnit.net 00:00:00.41] MyFirstUnitTests.UnitTest1.MyFirstTheory(value: 6) [FAIL]
失败 MyFirstUnitTests.UnitTest1.MyFirstTheory(value: 6) [3 ms]
错误消息:
Assert.True() Failure
Expected: True
Actual: False
堆栈跟踪:
at MyFirstUnitTests.UnitTest1.MyFirstTheory(Int32 value) in D:\malema.net\Exampels\MyFirstUnitTests\UnitTest1.cs:line 14
失败! - 失败: 1,通过: 2,已跳过: 0,总计: 3,持续时间: 4 ms - MyFirstUnitTests.dll (net5.0)
PS D:\malema.net\Exampels\MyFirstUnitTests>
可以看到成功了2个,失败了1个。
有时候我们的程序需要适能多个 目标框架,所以我们的测试程序也需要适应多个目标框架 我们可以打开 .csproj文件
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
把 TargetFramework
改成 TargetFrameworks
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;net5.0</TargetFrameworks>
</PropertyGroup>
dotnet test 支持 .NET Core(包括 .NET 5+)和 .NET Framework 目标的任意组合。 您甚至可以包含同一目标框架的多个版本。 应用程序作者通常只使用与应用程序打算在其上运行的目标框架相关的单个目标框架。 库作者更有可能使用多个目标框架,以确保他们的测试在所有支持的目标框架上成功运行。
<TargetFrameworks>net452;net461;net48;netcoreapp2.1;netcoreapp3.1;net5.0</TargetFrameworks>
让我们再跑一下单元测试
dotnet test
正在确定要还原的项目…
所有项目均是最新的,无法还原。
MyFirstUnitTests -> D:\malema.net\Exampels\MyFirstUnitTests\bin\Debug\netcoreapp3.1\MyFirstUnitTests.dll
MyFirstUnitTests -> D:\malema.net\Exampels\MyFirstUnitTests\bin\Debug\net5.0\MyFirstUnitTests.dll
D:\malema.net\Exampels\MyFirstUnitTests\bin\Debug\netcoreapp3.1\MyFirstUnitTests.dll (.NETCoreApp,Version=v3.1)的测试运行
Microsoft (R) 测试执行命令行工具版本 16.9.1
版权所有 (C) Microsoft Corporation。保留所有权利。
正在启动测试执行,请稍候...
总共 1 个测试文件与指定模式相匹配。
[xUnit.net 00:00:00.62] MyFirstUnitTests.UnitTest1.MyFirstTheory(value: 6) [FAIL]
失败 MyFirstUnitTests.UnitTest1.MyFirstTheory(value: 6) [5 ms]
错误消息:
Assert.True() Failure
Expected: True
Actual: False
堆栈跟踪:
at MyFirstUnitTests.UnitTest1.MyFirstTheory(Int32 value) in D:\malema.net\Exampels\MyFirstUnitTests\UnitTest1.cs:line 14
失败! - 失败: 1,通过: 2,已跳过: 0,总计: 3,持续时间: 6 ms - MyFirstUnitTests.dll (netcoreapp3.1)
D:\malema.net\Exampels\MyFirstUnitTests\bin\Debug\net5.0\MyFirstUnitTests.dll (.NETCoreApp,Version=v5.0)的测试运行
Microsoft (R) 测试执行命令行工具版本 16.9.1
版权所有 (C) Microsoft Corporation。保留所有权利。
正在启动测试执行,请稍候...
总共 1 个测试文件与指定模式相匹配。
[xUnit.net 00:00:00.39] MyFirstUnitTests.UnitTest1.MyFirstTheory(value: 6) [FAIL]
失败 MyFirstUnitTests.UnitTest1.MyFirstTheory(value: 6) [2 ms]
错误消息:
Assert.True() Failure
Expected: True
Actual: False
堆栈跟踪:
at MyFirstUnitTests.UnitTest1.MyFirstTheory(Int32 value) in D:\malema.net\Exampels\MyFirstUnitTests\UnitTest1.cs:line 14
失败! - 失败: 1,通过: 2,已跳过: 0,总计: 3,持续时间: 3 ms - MyFirstUnitTests.dll (net5.0)
会发现两个目标框架都有跑了