项目

微服务解决方案:编写单元与集成测试

必须拥有 ABP Business 或更高版本的许可证才能创建微服务解决方案。

单元测试和集成测试对于确保微服务系统的质量和可靠性至关重要。在本文档中,你将学习如何为你的微服务编写和运行测试。每个微服务都有自己的测试项目,用以验证其功能以及与其他服务的交互。测试主要分为四种类型:实体(Entities)仓储(Repositories)应用服务(Application Services)控制器(Controllers)

准备测试环境

在编写测试之前,你需要设置测试环境。微服务解决方案模板包含 MicroServiceNameTestsModuleMicroServiceNameTestBase 类,帮助你创建测试类并运行测试。在模块类中,你可以准备测试数据、配置数据库和设置测试环境。测试模块用于注册服务和配置测试环境,它会将微服务模块以 AdditionalAssembly 的形式注册到测试模块中。它不依赖于实际的微服务模块,因为微服务模块通常包含了针对开发和生产环境的特定配置。例如,它可能使用 Redis 作为分布式缓存,使用 RabbitMQ 作为分布式事件总线。然而,在测试环境中,使用内存缓存和内存事件总线就足够了。基类提供了辅助方法来访问服务和执行常见的测试操作。测试项目使用 xUnitShouldly 包来编写和运行测试。

单元测试

单元测试用于测试代码中的独立单元,以确保它们按预期工作。在微服务系统中,一个单元可以是一个方法、一个类或一个服务。单元测试的目标是验证软件中的每个单元都按照设计执行。

编写单元测试

你可以为微服务实体运行单元测试,以测试领域逻辑。你也可以为应用服务编写单元测试,以测试业务逻辑。然而,如果你有复杂的业务逻辑,可能需要编写集成测试来测试系统不同部分之间的交互。否则,你需要模拟应用服务的依赖项来编写单元测试。

以下是一个针对 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 类通过调用 PermissionGrantRepositoryGetListAsync 方法来测试其 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 类通过调用 PermissionAppServiceGetAsync 方法来测试其 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 方法来获取响应内容,从而测试 DemoControllerHelloWorld 操作。测试类继承自 AdministrationServiceIntegrationTestBase 类以访问服务和诸如 GetResponseAsStringAsync 的辅助方法。

运行测试

你可以使用 Visual Studio 的测试资源管理器或 dotnet test 命令来运行单元测试或集成测试。dotnet test 命令会运行解决方案中的所有测试。

dotnet test
在本文档中