agentsclimarketplace

Java testing

Skill mtkhawaja/java-skills/skills/java-testing

A Claude Code plugin and marketplace providing a skills library for high-quality Java development.

Install
npx -y skills add mtkhawaja/java-skills --skill java-testing

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use when writing or reviewing Java tests, unit or integration — JUnit Jupiter with AssertJ assertions, the @DisplayName / method-name mirroring convention, behavior-focused naming, Mockito (annotation mocks, no deep stubs, @MockitoBean for Spring), and Testcontainers with @ServiceConnection for real backing services (database, Kafka, Redis). Catches JUnit-assertion use, class-level @DisplayName, imperative or deep-stub mocking, H2-instead-of-real-DB, container-per-method, and slow/flaky suites.

SKILL.md

8.5 KB, as published. Nobody here has run it

Java Testing

Overview

Tests document behavior. The house stack: JUnit Jupiter for structure, AssertJ for assertions, Mockito (annotation-driven) for isolation, and Testcontainers + @ServiceConnection when a test needs a real backing service. For container lifecycle and suite-wide sharing details see references/testcontainers-patterns.md.

Structure & assertions

  • JUnit Jupiter (5+) by default, unless the repo standardizes on something else.
  • AssertJ for assertionsassertThat(x).isEqualTo(y) / assertThatThrownBy(...), never JUnit's assertEquals/assertTrue.
  • Every test has a method-level @DisplayName in natural language. Never at the class level (including @Nested).
  • The method name mirrors the @DisplayName in camelCase and describes behavior, not implementation: shouldDoXWhenY, shouldNotDoXWhenYIsCondition. Never a test prefix.
  • One behavior per test; order-independent and parallel-safe (no shared mutable state).
  • Prefer @ParameterizedTest for input matrices and edge-case grids over duplicated bodies.
  • Never skip/disable/comment out a test to make the build pass.
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;

class NotificationServiceTest {
    @DisplayName("Should save published event When the producer publishes a new event")
    @Test
    void shouldSavePublishedEventWhenTheProducerPublishesANewEvent() {
        assertThat(service.publish(event).status()).isEqualTo(Status.SAVED);
    }
}

Mockito

  • Use the JUnit Jupiter integration: @ExtendWith(MockitoExtension.class). Don't call MockitoAnnotations.openMocks(...) or create mocks imperatively with mock(...).
  • Prefer annotation mocks: @Mock, @Spy, @Captor, @InjectMocks.
  • Avoid brittle setups — no deep stubbing or mock-heavy tests tied to implementation details; prefer fakes or real collaborators. Stub only inside the test that needs it (no global stubbing).
  • For Spring-managed beans use @MockitoBean (prefer over the older @MockBean).
@ExtendWith(MockitoExtension.class)
class OrderServiceTest {
    @Mock OrderRepository repository;
    @InjectMocks OrderService service;
}

@SpringBootTest
class PaymentControllerTest {
    @MockitoBean PaymentService paymentService;   // prefer over @MockBean
}

Integration tests (Testcontainers)

Integration tests exercise the real backing service against production parity, fast and isolated:

  • Use a real engine via Testcontainers, not H2/in-memory. H2's compatibility mode hides dialect/type/identity/RETURNING differences — doubly true for Spring Data JDBC, which emits SQL almost literally. Match the prod engine and major version (postgres:16-alpine).
  • Wire it with @ServiceConnection (Spring Boot 3.1+, needs the spring-boot-testcontainers test dependency). It auto-creates the *ConnectionDetails bean — prefer it over manual @DynamicPropertySource, which is the older, more verbose fallback.
  • Container fields are static. A non-static @Container starts a fresh container per test method — slow. Static = once per class.
  • Share containers across the whole suite, not per class — a shared singleton (or a Spring-managed container in an imported @TestConfiguration base) so the suite starts one Postgres, not one per test class. See the reference.
  • Isolate state between tests. Don't let one test's data leak into another. Use @Transactional rollback (repository slice tests) or reset (truncate / Flyway clean) in setup; never rely on order.
  • Use the narrowest slice that exercises the behavior: @DataJdbcTest (JDBC beans only, rolls back per test) for repository tests; @SpringBootTest only when you need the full service path.
  • Separate integration tests from unit tests so a slow container suite doesn't run on every mvn test: name them *IT (Maven Failsafe) vs *Test (Surefire), and/or @Tag("integration").
  • Don't hand-manage start()/stop() for @Container fields (the extension owns the lifecycle) — only for the deliberate singleton/reuse patterns in the reference.
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
// ... plus the usual JUnit/AssertJ/Spring imports

@Testcontainers
@SpringBootTest
class OrderPersistenceIT {

    @Container
    @ServiceConnection                                 // auto-wires spring.datasource.* — no @DynamicPropertySource
    static final PostgreSQLContainer<?> POSTGRES = new PostgreSQLContainer<>("postgres:16-alpine");

    @Autowired OrderService orderService;
    @Autowired OrderRepository orderRepository;

    @DisplayName("Should persist order and read it back When place is called")
    @Test
    void shouldPersistOrderAndReadItBackWhenPlaceIsCalled() {
        var placed = orderService.place(new Order(null, "customer-42", BigDecimal.valueOf(99.95)));
        assertThat(orderRepository.findById(placed.id())).get()
            .satisfies(found -> assertThat(found.customerId()).isEqualTo("customer-42"));
    }
}

Common mistakes

RationalizationReality
"assertEquals is fine / imported"House standard is AssertJ — reads as behavior, better failures.
"@DisplayName on the @Nested class groups nicely"Class-level @DisplayName is forbidden; put it on each method.
"testGet is clear enough"Behavior names: shouldReturnAccountWhenIdExists. No test prefix.
"openMocks in @BeforeEach"Use @ExtendWith(MockitoExtension.class) + @Mock.
"Deep stubs keep the test short"Brittle — restructure or use a fake/real collaborator.
"I'll @Disabled this flaky one"Never disable tests to go green; fix the test or the code.
"H2 in-memory is faster for tests"It hides real SQL/dialect bugs — Spring Data JDBC especially. Use the prod engine.
"@DynamicPropertySource works fine"@ServiceConnection is the modern, terse replacement (Boot 3.1+).
"Each test/class gets its own container"Non-static @Container = container per method; per class is still slow at scale. static, shared across the suite.
"Integration tests run with the unit tests"Separate *IT/Failsafe from *Test/Surefire so mvn test stays fast.

Red flags — stop

  • org.junit.jupiter.api.Assertions / assertEquals imported
  • @DisplayName on a class or @Nested class; a test-prefixed name; name ≠ its @DisplayName
  • MockitoAnnotations.openMocks, imperative mock(...), deep stubs, @MockBean when @MockitoBean exists
  • Tests sharing static/mutable state, or depending on execution order / leftover data
  • H2/hsqldb/:mem: standing in for the production database
  • A non-static @Container; manual @DynamicPropertySource where @ServiceConnection applies
  • A @SpringBootTest where a @DataJdbcTest/@WebMvcTest slice would do

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.