微服务解决方案:编写单元与集成测试
必须拥有 ABP Business 或更高版本的许可证才能创建微服务解决方案。
单元测试和集成测试对于确保微服务系统的质量和可靠性至关重要。在本文档中,你将学习如何为你的微服务编写和运行测试。每个微服务都有自己的测试项目,用以验证其功能以及与其他服务的交互。测试主要分为四种类型:实体(Entities)、仓储(Repositories)、应用服务(Application Services) 和 控制器(Controllers)。
准备测试环境
在编写测试之前,你需要设置测试环境。微服务解决方案模板包含 MicroServiceNameTestsModule 和 MicroServiceNameTestBase 类,帮助你创建测试类并运行测试。在模块类中,你可以准备测试数据、配置数据库和设置测试环境。测试模块用于注册服务和配置测试环境,它会将微服务模块以 AdditionalAssembly 的形式注册到测试模块中。它不依赖于实际的微服务模块,因为微服务模块通常包含了针对开发和生产环境的特定配置。例如,它可能使用 Redis 作为分布式缓存,使用 RabbitMQ 作为分布式事件总线。然而,在测试环境中,使用内存缓存和内存事件总线就足够了。基类提供了辅助方法来访问服务和执行常见的测试操作。测试项目使用 xUnit 和 Shouldly 包来编写和运行测试。
单元测试
单元测试用于测试代码中的独立单元,以确保它们按预期工作。在微服务系统中,一个单元可以是一个方法、一个类或一个服务。单元测试的目标是验证软件中的每个单元都按照设计执行。
编写单元测试
你可以为微服务实体运行单元测试,以测试领域逻辑。你也可以为应用服务编写单元测试,以测试业务逻辑。然而,如果你有复杂的业务逻辑,可能需要编写集成测试来测试系统不同部分之间的交互。否则,你需要模拟应用服务的依赖项来编写单元测试。
以下是一个针对 PermissionDefinitionRecord 实体的单元测试示例:
public class PermissionDefinitionRecord_Tests
{
[Fact]
public void Should_Change_Name()
{
// 准备
var permission = new PermissionDefinitionRecord(
Guid.NewGuid(),
"test",
"test",
null,
"test"
);
permission.Name.ShouldBe("test");
// 执行
permission.Patch(new PermissionDefinitionRecord(
Guid.NewGuid(),
"test",
"test2",
null,
"test"));
// 断言
permission.Name.ShouldBe("test2");
}
}
在这个例子中,PermissionDefinitionRecord_Tests 类通过调用 PermissionDefinitionRecord 实体的 Patch 方法来测试其行为。测试方法 Should_Change_Name 准备了测试环境,调用了方法,并对结果进行了断言。由于这是一个单元测试,我们不需要继承 TestBase 类。
集成测试
集成测试用于测试系统不同部分之间的交互,以确保它们能够正确地协同工作。你可以为仓储、应用服务、控制器和其他组件编写集成测试,以验证它们的交互。
编写集成测试
微服务模板提供了一个用于编写集成测试的测试基类。你可以使用该基类来访问服务和执行常见的测试操作。
以下是一个针对仓储的集成测试示例:
public class PermissionGrantRepository_Tests : AdministrationServiceIntegrationTestBase
{
private readonly IPermissionGrantRepository _permissionGrantRepository;
public PermissionGrantRepository_Tests()
{
_permissionGrantRepository = GetRequiredService<IPermissionGrantRepository>();
}
[Fact]
public async Task Should_Get_Permissions_By_Role_Name()
{
var permissionGrants = await _permissionGrantRepository.GetListAsync(RolePermissionValueProvider.ProviderName, "admin");
permissionGrants.ShouldNotBeNull();
permissionGrants.Count.ShouldBeGreaterThanOrEqualTo(1);
}
}
在这个例子中,PermissionGrantRepository_Tests 类通过调用 PermissionGrantRepository 的 GetListAsync 方法来测试其 Should_Get_Permissions_By_Role_Name 方法。为了访问服务,测试类继承自 AdministrationServiceIntegrationTestBase 类,并使用 GetRequiredService 方法来获取服务实现。由于管理微服务测试模块在应用程序启动时已预置了测试数据,我们可以直接尝试获取管理员角色的权限。
类似地,你可以编写应用服务测试类来测试应用服务的业务逻辑:
public class PermissionAppService_Tests : AdministrationServiceIntegrationTestBase
{
private readonly IPermissionAppService _permissionAppService;
public PermissionAppService_Tests()
{
_permissionAppService = GetRequiredService<IPermissionAppService>();
}
[Fact]
public async Task Should_Get_Permissions()
{
var permissions= await _permissionAppService.GetAsync(RolePermissionValueProvider.ProviderName, "admin");
permissions.ShouldNotBeNull();
permissions.EntityDisplayName.ShouldBe("admin");
permissions.Groups.Count.ShouldBeGreaterThanOrEqualTo(1);
permissions.Groups.SelectMany(x => x.Permissions).Count().ShouldBeGreaterThanOrEqualTo(1);
}
}
在这个例子中,PermissionAppService_Tests 类通过调用 PermissionAppService 的 GetAsync 方法来测试其 Should_Get_Permissions 方法。测试类继承自 AdministrationServiceIntegrationTestBase 类以访问服务。
要测试控制器,你可以为控制器编写测试类并测试其操作:
public class DemoController_Tests : AdministrationServiceIntegrationTestBase
{
[Fact]
public async Task HelloWorld()
{
var response = await GetResponseAsStringAsync("/api/administration/demo/hello");
response.ShouldBe("Hello World!");
}
}
在这个例子中,DemoController_Tests 类通过调用 GetResponseAsStringAsync 方法来获取响应内容,从而测试 DemoController 的 HelloWorld 操作。测试类继承自 AdministrationServiceIntegrationTestBase 类以访问服务和诸如 GetResponseAsStringAsync 的辅助方法。
运行测试
你可以使用 Visual Studio 的测试资源管理器或 dotnet test 命令来运行单元测试或集成测试。dotnet test 命令会运行解决方案中的所有测试。
dotnet test
抠丁客


