引言
在现代化的软件开发中,单元测试 和集成测试 是确保代码质量和可靠性的关键部分。ASP.NET Core
社区内提供了强大的单元测试框架,xUnit
是其中之一,它提供了简单、清晰和强大的测试功能,编写单元测试有许多优点;有助于回归、提供文档及辅助良好的设计。下面几节我们来深入浅出探讨如何使用 xUnit
进行 ASP.NET Core
应用程序的单元测试和集成测试。
内容大纲:
xUnit 简介
xUnit.net
是一个免费、开源、面向社区的.NET
单元测试工具。由NUnit v2
的原始发明者编写,xUnit.net
是用于C#
和F#
(其他.NET
语言可能也可以使用,但不受支持)的最新技术单元测试。xUnit.net
可与Visual Studio
、Visual Studio Code
、ReSharper
、CodeRush
和TestDriven.NET
一起使用。它是.NET
基金会的一部分,并遵守其行为准则。其许可协议为 Apache 2(为 OSI 批准的许可协议)。
xUnit.net 官方网站
创建单元测试项目
在单元测试中通常要遵循AAA
模式,也就是 Arrange
、Act
、Assert
,这是一种常见的测试组织结构。
Arrange(准备)
: 在这个阶段,将设置测试的前提条件,初始化对象、设置输入参数等。简单讲就是准备测试环境,确保被测代码在正确的上下文中执行。Act(执行)
: 在这个阶段,会执行要测试的代码或方法。这是针对被测代码的实际调用或操作。Assert
: 在这个阶段,会验证被测代码的行为是否符合预期。检查实际结果与期望结果是否一致,如果不一致则测试失败。
示例:
c#
[Fact]
public void Add_EmptyString_ReturnsZero()
{
// Arrange
var stringCalculator = new StringCalculator();
// Act
var actual = stringCalculator.Add("");
// Assert
Assert.Equal(0, actual);
}
可读性是编写单元测试最重要的方面之一,在测试中分离这些操作 都明确地突出调用代码所需的依赖项、调用代码的方式以及尝试断言的内容,让测试尽可能具有可读性。
好了理解了这个核心概念我们可以先创建项目一步步的练习了。
用 VS 创建单元测试项目

在项目创建完之后我们可以简单浏览一下 xUnit
单元测试项目装了那些 nuget
依赖,做到对项目有个简单的了解
xml
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit" Version="2.5.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
</ItemGroup>
下面我们创建一个简单的数据计算类。
- 创建数学计算类
c#
public class MathCalculator
{
public int Add(int a, int b)
{
return a + b;
}
}
- 创建数据计算测试类
c#
public class MathCalculatorTests
{
[Fact]
public void Add_TwoNumbers_ReturnSum()
{
// Arrange
var calculator = new MathCalculator();
// Act
var result = calculator.Add(3, 5);
// Assert
Assert.Equal(8, result);
}
}
测试一下,测试类库右键->运行测试

可以看到 我们的单元测试通过。
单元测试命名规范
本着代码自文档的原则,测试的名称建议应包括三个部分:
- 要测试的方法的名称。
- 测试的方案。
- 调用方案时的预期行为。
示例
c#
[Fact]
public void Add_TwoNumbers_ReturnSum()
{
// Arrange
var calculator = new MathCalculator();
// Act
var result = calculator.Add(3, 5);
// Assert
Assert.Equal(8, result);
}
要测试的方法名称是 MathCalculator
中的 Add 方法,测试的方案是传两个数,预期是返回两数之和 按照上面的测试名称的命名规则可以命名为Add_TwoNumbers_ReturnSum
。
单元测试最佳命名规范应该包括三个关键部分:要测试的方法的名称、测试的场景,以及调用该场景时的预期行为。良好的命名标准能清晰表达测试意图,提供有效文档,便于他人理解代码行为和快速定位问题。
将方法标记为测试方法在
xUnit
中有两个属性,Fact
和Theory
Fact 属性
在方法上我们看到有一个 Attribute
[Fact] ,[Fact] 属性是 xUnit 中最基本的测试属性之一,用于标记一个方法作为一个无需参数且不返回任何内容的测试方法。被标记为 [Fact] 的方法将会被 xUnit
框架识别并执行.
Theory 属性
Theory
属性用于标记一个测试方法,该方法可以接受参数并运行多次,每次运行时使用不同的参数值。Theory 属性通常用于数据驱动测试,允许在同一个测试方法中使用不同的输入数据进行测试.
InlineData 属性
InlineData\] 属性指定这些输入 Theory 标记的测试方法的参数值。 *示例:* ```c# [Theory] [InlineData(-1)] [InlineData(0)] [InlineData(1)] public void IsPrime_ValuesLessThan2_ReturnFalse(int value) { var result = _primeService.IsPrime(value); Assert.False(result, $"{value} should not be prime"); } ``` > `InlineData` 适用于静态、硬编码的测试数据集合,适合于简单且固定的测试场景。 #### MemberData 属性 `MemberData` 属性是 `xUnit` 中用于数据驱动测试的一种方式,它允许从一个字段、属性或方法中获取测试数据,并将这些数据传递给测试方法进行多次测试。通过 `MemberData` 属性,可以更灵活地管理和提供测试数据,适用于需要动态生成测试数据的情况。 **使用方式** * 标记测试方法:使用 \[Theory\] 属性标记测试方法,以便接受从 MemberData 属性提供的测试数据。 * 准备测试数据:创建一个公共静态字段、属性或方法,该字段、属性或方法返回一个 IEnumerable\