本教程逐步讲解了构建示例解决方案的交互式体验,以学习单元测试概念。 如果希望使用预构建解决方案学习本教程,请在开始前查看或下载示例代码。 有关下载说明,请参阅 示例和教程。
本文介绍如何测试 .NET Core 项目。 如果要测试 ASP.NET Core 项目,请参阅 ASP.NET Core中的
先决条件
- 最新的 .NET SDK
- Visual Studio Code 编辑器
- C# 开发套件
创建源项目
打开 shell 窗口。 创建名为 unit-testing-using-mstest 的目录来保存解决方案。 在此新目录中,运行 dotnet new sln 为类库和测试项目创建新的解决方案文件。 创建 PrimeService 目录。 到目前为止,以下大纲显示了目录和文件结构:
/unit-testing-using-mstest
unit-testing-using-mstest.sln
/PrimeService
将 PrimeService 设为当前目录,并运行 dotnet new classlib 来创建源项目。
将目录更改回 unit-testing-using-mstest 目录。 运行 dotnet sln add 以将类库项目添加到解决方案:
dotnet sln add PrimeService/PrimeService.csproj
将 PrimeService 目录中的 Class1.cs 重命名为 PrimeService.cs。 将文件中的代码替换为以下代码,以创建类的 PrimeService 失败实现:
using System;
namespace Prime.Services
{
public class PrimeService
{
public bool IsPrime(int candidate)
{
throw new NotImplementedException("Please create a test first.");
}
}
}
创建测试项目
创建 PrimeService.Tests 目录。 以下大纲显示了目录结构:
/unit-testing-using-mstest
unit-testing-using-mstest.sln
/PrimeService
Source Files
PrimeService.csproj
/PrimeService.Tests
将 PrimeService.Tests 目录设置为当前目录,并使用 dotnet new mstest创建新项目。 dotnet new 命令创建一个使用 MSTest 作为测试库的测试项目。 该模板在 PrimeServiceTests.csproj 文件中配置测试运行程序:
<ItemGroup>
<PackageReference Include="MSTest" Version="4.1.0" />
</ItemGroup>
Note
显示的包版本是示例。 由 dotnet new mstest 生成的版本取决于你的 .NET SDK。 模板和下载的示例可能不会使用最新的 NuGet 包版本。
若要在创建和运行测试后检查更新,请从测试项目目录运行 dotnet package list --outdated 。 使用 dotnet package add <PACKAGE_NAME> 将包引用更新为最新的兼容稳定版本。 更新前请查看发行说明中的破坏性变更,更新完成后,再次运行 dotnet test。
如果你使用的是 .NET 9 SDK 或更早版本,请改用 dotnet list package --outdated 和 dotnet add package <PACKAGE_NAME>。
测试项目需要其他包来创建和运行单元测试。
dotnet new 在上一步中添加了代码覆盖率报告所需的 MSTest 包和工具。
将 PrimeService 类库添加为项目的另一个依赖项。 使用 dotnet reference add 命令:
dotnet reference add ../PrimeService/PrimeService.csproj
可以在 GitHub 上的 示例存储库 中看到整个文件。
以下大纲显示了最终解决方案布局:
/unit-testing-using-mstest
unit-testing-using-mstest.sln
/PrimeService
Source Files
PrimeService.csproj
/PrimeService.Tests
Test Source Files
PrimeServiceTests.csproj
更改为 unit-testing-using-mstest 目录,然后运行 dotnet sln add:
dotnet sln add ./PrimeService.Tests/PrimeService.Tests.csproj
创建第一个测试
编写失败的测试,使其通过,然后重复该过程。 从 PrimeService.Tests 目录中删除UnitTest1.cs,并创建包含以下内容的名为PrimeService_IsPrimeShould.cs的新 C# 文件:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Prime.Services;
namespace Prime.UnitTests.Services
{
[TestClass]
public class PrimeService_IsPrimeShould
{
private readonly PrimeService _primeService;
public PrimeService_IsPrimeShould()
{
_primeService = new PrimeService();
}
[TestMethod]
public void IsPrime_InputIs1_ReturnFalse()
{
bool result = _primeService.IsPrime(1);
Assert.IsFalse(result, "1 shouldn't be prime");
}
}
}
TestClass 属性表示包含单元测试的类。 TestMethod 属性指示方法是测试方法。
MSTest 为每个测试创建测试类的新实例,因此构造函数为每个测试创建一个单独的 PrimeService 实例。 构造函数仅包含此类中每个测试都需要的设置。 如果测试需要不同的设置,请在测试方法中创建对象,或从这些方法调用帮助程序方法。 有关指导,请参阅使用帮助程序而非 Setup 和 Teardown。
保存此文件并执行 dotnet test 以生成测试和类库,然后运行测试。 MSTest 测试运行程序包含要运行测试的程序入口点。
dotnet test 使用创建的单元测试项目启动测试运行程序。
测试失败,因为你尚未创建实现。 在起作用的 PrimeService 类中编写最简单的代码,使此测试通过:
public bool IsPrime(int candidate)
{
if (candidate == 1)
{
return false;
}
throw new NotImplementedException("Please create a test first.");
}
在 unit-testing-using-mstest 目录中,再次运行 dotnet test 。
dotnet test 命令构建 PrimeService 项目,然后构建 PrimeService.Tests 项目。 生成这两个项目后,它将运行此单个测试。 测试通过。
添加更多功能
你已经通过了一个测试,现在可以编写更多测试。 质数有其他几种简单情况:0,-1。 可以使用 TestMethod 属性添加新测试,但这很快变得繁琐。 还有其他 MSTest 属性可用于编写一套类似的测试。 测试方法可以执行相同的代码,但具有不同的输入参数。 可以使用 DataRow 属性 为这些输入指定值。
不要创建新的测试,而是应用这两个属性来创建单个数据驱动测试。 数据驱动测试是一种测试小于 2 的多个值(即最低质数)的方法。 在 PrimeService_IsPrimeShould.cs 中添加新的测试方法:
[TestMethod]
[DataRow(-1)]
[DataRow(0)]
[DataRow(1)]
public void IsPrime_ValuesLessThan2_ReturnFalse(int value)
{
bool result = _primeService.IsPrime(value);
Assert.IsFalse(result, $"{value} should not be prime");
}
运行 dotnet test,两项测试均失败。 若要使所有测试通过,可以在 PrimeService.cs 文件中更改 if 方法开头的 IsPrime 子句:
if (candidate < 2)
继续通过在主库中添加测试、理论和代码来进行迭代。 你将拥有已完成的测试版本和库的完整实现。
你为该库构建了一个小库和一组单元测试。 你构建了解决方案,以便添加新的包和测试是正常工作流的一部分。 你大部分时间都专注于解决应用程序的目标。
在 Azure Pipelines 中运行测试
若要在推送更改时自动运行测试,请将Azure Pipelines配置添加到包含已完成解决方案的存储库。 你需要一个 Azure DevOps 项目,并且有权访问 Microsoft 托管的代理。 有关先决条件,请参阅 创建第一个管道。
在存储库的根目录下,创建一个包含以下内容的
azure-pipelines.yml文件。 该示例假设PrimeService和PrimeService.Tests目录位于存储库根目录下,并且两个项目都以 .NET 10 为目标。trigger: - main pool: vmImage: ubuntu-latest steps: - task: UseDotNet@2 displayName: Install .NET SDK inputs: packageType: sdk version: 10.0.x - task: DotNetCoreCLI@2 displayName: Run MSTest tests inputs: command: test projects: PrimeService.Tests/PrimeService.Tests.csproj arguments: --configuration Release publishTestResults: true调整配置以匹配存储库:
- 如果你的分支名称不同,请将
trigger中的main替换为该分支名称。 - 如果解决方案位于子目录中,请将
projects更新为测试项目相对于存储库根目录的路径。 - 如果项目面向不同的 .NET 版本,请在
version任务中更改UseDotNet@2以匹配。 例如,对于以net8.0为目标的项目,请使用8.0.x。 如果存储库包含文件global.json,请确保已安装的 SDK 满足其版本要求。
- 如果你的分支名称不同,请将
提交解决方案和
azure-pipelines.yml文件并将其推送到 Git 存储库。在Azure DevOps项目中,选择管道>新建管道,如果这是你的第一个管道,则选择创建管道。 选择存储库提供程序和存储库。
在配置管道页面上,选择现有 Azure 管道 YAML 文件,选择该分支和
/azure-pipelines.yml,然后选择继续。 查看配置并选择“ 运行”。
该UseDotNet@2任务将安装 .NET SDK。
DotNetCoreCLI@2 任务运行dotnet test,用于还原依赖项、生成测试项目及其引用的库,并在发布配置中运行测试。
使用 publishTestResults: true,即使测试失败,任务也会生成 TRX 结果文件并发布结果。 运行后,打开管道运行的 “测试” 选项卡,查看已通过的测试和失败的测试。 失败的测试还会导致测试任务和管道失败。
Note
此示例使用来自 dotnet new mstest 的默认 VSTest 配置,并配合 .NET 10 SDK。 如果启用 Microsoft.Testing.Platform (MTP),有关所需的运行程序配置,请参阅在持续集成中运行 MTP 测试。