单元测试
由于跨平台应用将在现实世界中使用,因此应该对其进行测试,以提高其质量、可靠性和性能。 应在应用上执行许多类型的测试,包括单元测试、集成测试和用户界面测试。 单元测试是最常见的测试形式,对于构建高质量的应用至关重要。
单元测试采用应用的一个较小单元(通常是某个方法),将其与其余代码相隔离,并验证其行为是否符合预期。 其目标是检查每个功能单元是否按预期执行,以便错误不会在整个应用中传播。 在发生 bug 的位置检测 bug,比在次要故障点位置间接观察 bug 造成的影响更为有效。
单元测试通常使用安排-行动-断言模式:
步骤 | 说明 |
---|---|
排列 | 初始化对象,并设置传递给受测方法的数据的值。 |
行动 | 使用所需参数调用受测方法。 |
Assert | 验证受测方法的操作行为是否符合预期。 |
此模式可确保单元测试可读、自描述和一致。
如果将单元测试规划为软件开发工作流不可或缺的一部分,则单元测试对代码质量的影响最为显著。 单元测试可以充当应用的设计文档和功能规范。 一旦编写了方法,就应该编写单元测试来验证该方法响应标准、边界和不正确输入数据情况的行为,并检查代码做出的任何显式或隐式假设。 或者,如果使用测试驱动开发,则会在代码之前编写单元测试。
重要
单元测试对回归非常有效。 也就是说,功能曾经正常工作,但被错误的更新所干扰。
xUnit 是建议用于 .NET MAUI 应用的测试框架。
将 xUnit 测试添加到 .NET MAUI 解决方案
若要将 xUnit 测试添加到 .NET MAUI 解决方案,请执行以下操作之一:
使用 Visual Studio 将新的 xUnit 测试项目添加到解决方案。
OR
使用 .NET CLI 创建新的 xUnit 测试项目,并将其添加到解决方案。 有关详细信息,请参阅在 .NET 中使用 dotnet test 和 xUnit 进行 C# 单元测试。
xUnit 测试项目的项目文件 (.csproj) 如以下示例所示:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<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>
<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>
</Project>
$(TargetFramework)
生成属性指定测试项目的目标框架。 此框架是计算机上安装的最新版 .NET。
xunit
包引入子包,其中包含测试框架本身,以及用于通过单元测试检测常见问题的 Roslyn 分析器。 在 Visual Studio 中以及通过 dotnet test
命令运行单元测试时需要 xunit.runner.visualstudio
和 Microsoft.NET.Test.Sdk
包。 coverlet.collector
包可用于收集代码覆盖率。 如果你不打算收集代码覆盖率,可以删除此包引用。 有关单元测试的代码覆盖率的详细信息,请参阅使用代码覆盖率进行单元测试。
可通过两种主要方法为应用构建单元测试:
- 要进行单元测试的代码位于 .NET MAUI 类库项目中。
- 要进行单元测试的代码位于 .NET MAUI 应用项目中。
每种方法都需要特定的配置。
配置 .NET MAUI 类库项目以进行单元测试
使用此方法时,要进行单元测试的代码位于 .NET MAUI 应用项目使用的 .NET MAUI 类库项目中。 若要针对 .NET MAUI 类库编写单元测试,需要更新项目使用的目标框架。 为此,可将 xUnit 测试项目文件 (.csproj) 中 $(TargetFramework)
生成属性的值添加到 .NET MAUI 类库项目文件中的 $(TargetFrameworks)
生成属性:
<TargetFrameworks>net8.0;net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks>
在此示例中,net8.0
的值已添加到 .NET MAUI 类库项目文件中的 $(TargetFrameworks)
生成属性。
然后,必须从 xUnit 测试项目添加对 .NET MAUI 类库项目的引用。
配置 .NET MAUI 应用项目以进行单元测试
使用此方法时,要进行单元测试的代码位于.NET MAUI 应用项目中。 若要针对 .NET MAUI 应用项目编写单元测试,需要更新项目使用的目标框架。 为此,可将 xUnit 测试项目文件 (.csproj) 中 $(TargetFramework)
生成属性的值添加到 .NET MAUI 应用项目文件中的 $(TargetFrameworks)
生成属性:
<TargetFrameworks>net8.0;net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks>
在此示例中,net8.0
的值已添加到 .NET MAUI 应用项目文件中的 $(TargetFrameworks)
生成属性。
还需要修改 .NET MAUI 应用项目,使其不会输出 xUnit 测试项目使用的目标框架的可执行文件。 为此,可将一个条件添加到 .NET MAUI 应用项目文件中的 $(OutputType)
生成属性:
<OutputType Condition="'$(TargetFramework)' != 'net8.0'">Exe</OutputType>
在此示例中,仅当目标框架不是 net8.0
时,.NET MAUI 应用项目才会生成可执行文件。
然后,必须从 xUnit 测试项目添加对 .NET MAUI 应用项目的引用。
写入单元测试
xUnit 支持两种不同类型的单元测试:
测试类型 | 属性 | 说明 |
---|---|---|
事实 | Fact |
始终为 true 的测试,用于测试固定条件。 |
理论 | Theory |
只对特定数据集成立的测试。 |
应将单元测试放在 xUnit 测试项目中,并使用 [Fact]
或 [Theory]
属性对其进行修饰。 以下示例演示了使用 [Fact]
属性的单元测试:
namespace MyUnitTests
{
public class MyTests
{
[Fact]
public void PassingTest()
{
Assert.AreEqual(4, 2+2);
}
[Fact]
public void FailingTest()
{
Assert.AreEqual(5, 2+2);
}
}
}
在此示例中,测试代表有意通过和失败的测试。
以下示例演示了使用 [Theory]
属性的单元测试:
namespace MyUnitTests
{
public class MyTests
{
[Theory]
[InlineData(3)]
[InlineData(4)]
[InlineData(5)]
public void MyTheoryTest(int value)
{
Assert.True(value % 2 == 1);
}
}
}
在此示例中,尽管只有一个测试方法,但实际上有三个测试,因为将对每个数据项运行理论测试一次。
提示
每个单元测试将测试一个操作。 随着测试复杂性的扩大,测试的验证变得更加困难。 通过将单元测试限制为单个关注点,能够确保测试可重复且独立,并可缩短执行时间。 有关详细信息,请参阅单元测试最佳做法。
运行单元测试
单元测试可以在 Visual Studio 的测试资源管理器中运行,或者使用 dotnet test
命令来运行。 有关测试资源管理器的信息,请参阅使用测试资源管理器运行单元测试。 有关 dotnet test
命令的详细信息,请参阅在 .NET 中使用 dotnet test 和 xUnit 进行 C# 单元测试和 dotnet test。
使用设备运行器运行单元测试
还可以使用设备运行器在设备上运行单元测试。 设备运行器是一个测试运行器应用,它提供了可以通过 XHarness 从 CLI 运行的视觉运行器 shell 和一些挂钩。 有关详细信息,请参阅测试设备运行器 wiki 中的文档。