使用 MSTest 和 .NET 对 C# 进行单元测试

本教程逐步讲解了构建示例解决方案的交互式体验,以学习单元测试概念。 如果希望使用预构建解决方案学习本教程,请在开始前查看或下载示例代码。 有关下载说明,请参阅 示例和教程

本文介绍如何测试 .NET Core 项目。 如果要测试 ASP.NET Core 项目,请参阅 ASP.NET Core中的 集成测试。

先决条件

创建源项目

打开 shell 窗口。 创建名为 unit-testing-using-mstest 的目录来保存解决方案。 在此新目录中,运行 dotnet new sln 为类库和测试项目创建新的解决方案文件。 创建 PrimeService 目录。 到目前为止,以下大纲显示了目录和文件结构:

/unit-testing-using-mstest
    unit-testing-using-mstest.sln
    /PrimeService

PrimeService 设为当前目录,并运行 dotnet new classlib 来创建源项目。 将 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.");
        }
    }
}

将目录更改回 unit-testing-using-mstest 目录。 运行 dotnet sln add 以将类库项目添加到解决方案:

dotnet sln add PrimeService/PrimeService.csproj

创建测试项目

创建 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="3.2.0" />
  <PackageReference Include="Microsoft.Testing.Extensions.CodeCoverage" Version="17.10.1" />
</ItemGroup>

测试项目需要其他包来创建和运行单元测试。 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 should not be prime");
        }
    }
}

TestClass 属性表示包含单元测试的类。 TestMethod 属性指示方法是测试方法。

保存此文件并执行 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 testdotnet 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)
{
    var result = _primeService.IsPrime(value);

    Assert.IsFalse(result, $"{value} should not be prime");
}

运行 dotnet test,两项测试均失败。 若要使所有测试通过,可以在 PrimeService.cs 文件中更改 if 方法开头的 IsPrime 子句

if (candidate < 2)

继续通过在主库中添加测试、理论和代码来进行迭代。 你将拥有已完成的测试版本库的完整实现

你已为该库生成了一个小库和一组单元测试。 你已构建解决方案,以便添加新包和测试是正常工作流的一部分。 你大部分时间都专注于解决应用程序的目标。

另请参阅