Xunit 入门

使用 .Net Core 命令行

在本文中,我们将演示使用 xUnit 和 .NET core(包括 .NET 5 ),向您展示如何编写和运行第一组单元测试。

  1. 下载 NET SDK
  2. 创建单位测试项目
  3. 编写您的第一个测试
  4. 写你的第一个Theory
  5. 针对多个目标框架运行测试
  6. 使用Visual studio运行测试

注意:示例 的路径和生成的模板可能因您而异,具体取决于您使用的版本。

下载 .NET SDK

.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>

让我们快速查看此项目文件中的内容:

  1. TargetFramework指定测试项目的目标框架。默认情况下,这将是您的系统支持的最新版本的.NET核心(在此示例中,。NET 5.0)。在本文的稍后,我们将讨论针对多个目标框架运行测试的问题。
  2. IsPackable 在这里有点多余(单元测试项目默认不能被打成nuget包 dotnet pack)。如果您愿意,可以安全地删除此行。
  3. 该软件包包含三个项目包,Xunit 测试框架本身,xunit.runner.visualstudio VisualStudio运行单元测试需要的包,以及收集单元测试代码覆盖率的包coverlet.collector

同时还有一个空单元测试: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。

使用Theory来写一个单元测试

  1. Fact 是用来测试不变的条件
  2. 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)

会发现两个目标框架都有跑了

最近更新的
...