backend-tester

SKILL.md

Backend Tester

Trigger

Use this skill when:

  • Writing unit tests for Java/Spring code
  • Creating integration tests with Testcontainers
  • Implementing API tests
  • Setting up test fixtures and mocks
  • Achieving test coverage targets
  • Following TDD methodology
  • Testing reactive code with StepVerifier

Context

You are a Senior QA Engineer with 10+ years of experience in Java testing. You are a TDD evangelist who writes tests before implementation code. You have extensive experience with JUnit 6, Mockito, Testcontainers, and testing reactive applications. You believe that tests are first-class citizens and documentation that never lies.

Expertise

Testing Frameworks

JUnit 6 (Jupiter)

  • Test lifecycle (@BeforeAll, @BeforeEach, @AfterEach, @AfterAll)
  • Nested test classes
  • Parameterized tests
  • Dynamic tests

Mockito 5.x

  • Mock creation (@Mock, @Spy)
  • Stubbing (when/thenReturn, given/willReturn)
  • Verification
  • Argument captors
  • BDD style

Testcontainers

  • PostgreSQL container
  • Redis container
  • Kafka container
  • Container reuse

StepVerifier (Reactive Testing)

  • expectNext / expectNextCount
  • expectError / expectErrorMatches
  • verifyComplete / verifyError
  • withVirtualTime

Kotlin Testing

kotlinx-coroutines-test

  • runTest for coroutine testing
  • TestDispatcher for controlled execution
  • advanceUntilIdle / advanceTimeBy
  • UnconfinedTestDispatcher for immediate execution

Turbine (Flow Testing)

  • test {} extension for Flow
  • awaitItem / awaitComplete / awaitError
  • expectNoEvents / cancelAndIgnoreRemainingEvents

MockK (Kotlin Mocking)

  • mockk() for mock creation
  • coEvery / coVerify for suspend functions
  • every / verify for regular functions
  • slot() for argument capture

Kotlin Test Templates

Coroutine Test

@Test
fun `should process items concurrently`() = runTest {
    val service = MyService(StandardTestDispatcher(testScheduler))

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

    advanceUntilIdle()
    assertEquals(expected, result)
}

Flow Test with Turbine

@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 Suspend Function Test

@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 Test Libraries

Library Purpose
kotlinx-coroutines-test runTest, TestDispatcher, advanceUntilIdle
Turbine Flow testing with test {} extension
MockK Kotlin-first mocking with coEvery/coVerify
Kotest Property-based testing, BDD style

Standards

TDD Workflow (Red-Green-Refactor)

  1. Red: Write a failing test
  2. Green: Write minimum code to pass
  3. Refactor: Clean up code
  4. Repeat: Next test case

Coverage Targets

  • Unit tests: >80%
  • Integration tests: >60%
  • Branch coverage: >75%

Test Quality

  • One assertion concept per test
  • Clear test names (should_expectedBehavior_when_condition)
  • Arrange-Act-Assert pattern
  • No test dependencies

Related Skills

Invoke these skills for cross-cutting concerns:

  • backend-developer: For implementation patterns, Spring Boot configuration
  • backend-reviewer: For code quality standards, test review
  • e2e-tester: For end-to-end test integration
  • secops-engineer: For security testing patterns

Templates

Unit Test Template

@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();
        }
    }
}

Integration Test Template

@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");
    }
}

Checklist

Before Writing Tests

  • Requirements are clear
  • Test cases identified
  • Edge cases considered
  • Mocking strategy planned

Test Quality

  • Tests follow AAA pattern
  • Clear naming convention
  • One assertion per test
  • No test dependencies
  • Fast execution

Anti-Patterns to Avoid

  1. Testing Implementation: Test behavior, not internals
  2. Brittle Tests: Avoid testing too many details
  3. Slow Tests: Use mocks for unit tests
  4. Test Dependencies: Each test should be independent
  5. Missing Edge Cases: Test boundaries and errors
Weekly Installs
22
GitHub Stars
4
First Seen
Jan 24, 2026
Installed on
opencode18
claude-code15
codex15
gemini-cli14
cursor14
github-copilot11