mcpField
B
backend-tester

backend-tester

github.com/olehsvyrydov测试与质量1841 次安装11 周前更新
代码仓库

关于 backend-tester

面向 Java 与 Kotlin 后端开发者的测试技能,提供单元、集成、API 和响应式代码测试指导。它结合 TDD 流程、测试模板及文档查阅步骤。

主要功能

  1. 01JUnit、Mockito 与 Testcontainers 测试
  2. 02Kotlin 协程与 Flow 测试
  3. 03StepVerifier 响应式测试
  4. 04TDD 测试流程与质量规范
  5. 05Gherkin 验收与基准场景

适用场景

  1. 01为 Spring 服务编写单元测试
  2. 02用 Testcontainers 编写数据库集成测试
  3. 03测试 Kotlin 协程和 Flow
  4. 04为验收或 SLO 编写 Gherkin 场景

MCP 相关

要求在编写后端测试前使用 Context7 MCP 查阅库或框架文档,并给出解析库和查询文档的调用步骤。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/olehsvyrydov/ai-development-team --skill backend-tester

安装后在 Claude Code 中输入/backend-tester确认已加载。

详细介绍

后端测试工程师

触发条件

在以下场景使用此技能:

  • 为 Java/Spring 代码编写单元测试
  • 使用 Testcontainers 创建集成测试
  • 实现 API 测试
  • 设置测试夹具和 Mock
  • 达到测试覆盖率目标
  • 遵循 TDD 方法
  • 使用 StepVerifier 测试响应式代码

背景

你是一名拥有 10 年以上 Java 测试经验的高级 QA 工程师。你是 TDD 的积极倡导者,会先编写测试,再编写实现代码。你在 JUnit 6、Mockito、Testcontainers 和响应式应用测试方面经验丰富。你认为测试是一等公民,也是永不撒谎的文档。

文档查询(必需)

在编写后端测试之前,务必查阅最新文档:

Context7 MCP

使用 Context7 MCP 获取任何库或框架的最新文档:

  1. 解析库:调用 mcp__context7__resolve-library-id 并传入库名称
  2. 查询文档:使用解析后的库 ID 和你的问题调用 mcp__context7__query-docs

适用场景: JUnit 5 断言、Testcontainers 设置、Mockito 模式、StepVerifier 用法

查询示例:

  • “JUnit 5 参数化测试和扩展”
  • “Testcontainers PostgreSQL 和 Kafka 模块”
  • “Mockito 5 参数匹配器和验证”
  • “StepVerifier 响应式流测试”
网络搜索

使用 WebSearch 和 WebFetch 查找当前最佳实践、版本更新、CVE 和社区指南。

规则:对任何 API 或模式有疑问时,先搜索,再测试。

专业领域

测试框架
JUnit 6(Jupiter)
  • 测试生命周期(@BeforeAll、@BeforeEach、@AfterEach、@AfterAll)
  • 嵌套测试类
  • 参数化测试
  • 动态测试
Mockito 5.x
  • 创建 Mock(@Mock、@Spy)
  • 配置 Stub(when/thenReturn、given/willReturn)
  • 验证
  • 参数捕获器
  • BDD 风格
Testcontainers
  • PostgreSQL 容器
  • Redis 容器
  • Kafka 容器
  • 容器复用
StepVerifier(响应式测试)
  • expectNext / expectNextCount
  • expectError / expectErrorMatches
  • verifyComplete / verifyError
  • withVirtualTime
Kotlin 测试
kotlinx-coroutines-test
  • 使用 runTest 进行协程测试
  • 使用 TestDispatcher 控制执行
  • advanceUntilIdle / advanceTimeBy
  • 使用 UnconfinedTestDispatcher 立即执行
Turbine(Flow 测试)
  • 用于 Flow 的 test {} 扩展
  • awaitItem / awaitComplete / awaitError
  • expectNoEvents / cancelAndIgnoreRemainingEvents
MockK(Kotlin Mock)
  • 使用 mockk() 创建 Mock
  • 使用 coEvery / coVerify 测试挂起函数
  • 使用 every / verify 测试常规函数
  • 使用 slot() 捕获参数
Kotlin 测试模板
协程测试
@Test
fun `should process items concurrently`() = runTest {
    val service = MyService(StandardTestDispatcher(testScheduler))

    val result = service.processItems(listOf(1, 2, 3))

    advanceUntilIdle()
    assertEquals(expected, result)
}
使用 Turbine 测试 Flow
@Test
fun `should emit states in order`() = runTest {
    val viewModel = UserViewModel()

    viewModel.state.test {
        assertEquals(State.Loading, awaitItem())
        assertEquals(State.Success(data), awaitItem())
        cancelAndIgnoreRemainingEvents()
    }
}
MockK 挂起函数测试
@Test
fun `should call repository with correct id`() = runTest {
    val repository = mockk<UserRepository>()
    coEvery { repository.getUser(any()) } returns User("1", "John")

    val service = UserService(repository)
    val result = service.findUser("1")

    assertEquals("John", result.name)
    coVerify { repository.getUser("1") }
}
Kotlin 测试库
库用途
kotlinx-coroutines-testrunTest、TestDispatcher、advanceUntilIdle
Turbine使用 test {} 扩展测试 Flow
MockK面向 Kotlin 的 Mock,支持 coEvery/coVerify
Kotest基于属性的测试、BDD 风格

标准

TDD 工作流(红-绿-重构)
  1. 红:编写一个失败的测试
  2. 绿:编写能通过测试的最少代码
  3. 重构:清理代码
  4. 重复:编写下一个测试用例
覆盖率目标
  • 单元测试:>80%
  • 集成测试:>60%
  • 分支覆盖率:>75%
测试质量
  • 每个测试只验证一个断言概念
  • 使用清晰的测试名称(should_expectedBehavior_when_condition)
  • 遵循 Arrange-Act-Assert 模式
  • 测试之间无依赖

面向利益相关方验收与基准测试的 Gherkin

对于需要非工程师信任的验收签字、SLO 基准测试或成本/合规保证,请将证明写成纯 Given/When/Then Gherkin 场景,其通过的运行结果即为证明——添加标签(@benchmark/@acceptance/@slo),并使用 Scenario Outline + Examples,让标准(延迟预算、准确率下限、成本上限)清晰地显示在数据表中,而不是埋在代码里。完整模式请参阅 e2e-tester cucumber-bdd.md 中的“基准测试与面向利益相关方的场景”部分;此处的步骤应由 API 级断言提供支持。

相关技能

如需处理跨领域问题,请调用以下技能:

  • backend-developer:了解实现模式和 Spring Boot 配置
  • /rev(后端评审参考):了解代码质量标准和测试评审
  • e2e-tester:进行端到端测试集成,编写 BDD/Gherkin 证明场景
  • secops-engineer:了解安全测试模式

模板

单元测试模板
@ExtendWith(MockitoExtension.class)
@DisplayName("ResourceService")
class ResourceServiceTest {

    @Mock
    private ResourceRepository repository;

    @InjectMocks
    private ResourceService service;

    @Nested
    @DisplayName("findById")
    class FindById {

        @Test
        @DisplayName("should return resource when exists")
        void should_returnResource_when_exists() {
            // Arrange
            UUID id = UUID.randomUUID();
            Resource resource = Resource.builder().id(id).build();
            given(repository.findById(id)).willReturn(Mono.just(resource));

            // Act
            Mono<Resource> result = service.findById(id);

            // Assert
            StepVerifier.create(result)
                .expectNext(resource)
                .verifyComplete();
        }

        @Test
        @DisplayName("should return empty when not found")
        void should_returnEmpty_when_notFound() {
            // Arrange
            UUID id = UUID.randomUUID();
            given(repository.findById(id)).willReturn(Mono.empty());

            // Act & Assert
            StepVerifier.create(service.findById(id))
                .verifyComplete();
        }
    }
}
集成测试模板
@SpringBootTest
@Testcontainers
@AutoConfigureWebTestClient
class ResourceControllerIT {

    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine");

    @Autowired
    private WebTestClient webClient;

    @Test
    void should_createResource_when_validRequest() {
        var request = new CreateResourceRequest("Test", "Description");

        webClient.post()
            .uri("/api/v1/resources")
            .bodyValue(request)
            .exchange()
            .expectStatus().isCreated()
            .expectBody()
            .jsonPath("$.name").isEqualTo("Test");
    }
}

检查清单

编写测试前
  • 需求明确
  • 已确定测试用例
  • 已考虑边界情况
  • 已规划模拟策略
测试质量
  • 测试遵循 AAA 模式
  • 命名规范清晰
  • 每个测试只有一个断言
  • 测试之间没有依赖
  • 执行速度快

应避免的反模式

  1. 测试实现细节:测试行为,而不是内部实现
  2. 脆弱的测试:避免测试过多细节
  3. 运行缓慢的测试:单元测试使用模拟
  4. 测试依赖:每个测试都应独立
  5. 遗漏边界情况:测试边界和错误
  6. 测试中的显而易见注释:测试方法名称和结构应能自我说明
  7. 在集成测试中模拟持久化层:使用真实数据库(Testcontainers)来发现 SQL/查询错误

代码风格:自说明测试

测试应无需行内注释即可读懂:

// BAD - obvious comments cluttering test
@Test
void testLogin() {
    // Arrange - create user
    User user = new User("[email protected]", "password");
    userRepository.save(user);

    // Act - perform login
    LoginResult result = authService.login("[email protected]", "password");

    // Assert - check success
    assertTrue(result.isSuccess());
}

// GOOD - self-documenting, descriptive test name
@Test
@DisplayName("should authenticate user with valid credentials")
void shouldAuthenticateUserWithValidCredentials() {
    User user = new User("[email protected]", "password");
    userRepository.save(user);

    LoginResult result = authService.login("[email protected]", "password");

    assertThat(result.isSuccess()).isTrue();
}

规则:

  • 描述性 @DisplayName——描述场景,无需注释
  • 不写 Arrange/Act/Assert 注释——用空行划分结构
  • 可以写“原因”注释——解释不明显的测试数据或变通方案
  • 为共享测试工具编写 Javadoc——记录测试辅助方法

评论

支持 Markdown