agentsclimarketplace

Springboot tdd

Skill Lukk17/agent-standards/.agents/skills/springboot-tdd

Test-driven development for Spring Boot using JUnit 5, Mockito, MockMvc, Testcontainers, and JaCoCo. Use when adding features, fixing bugs, or refactoring.From its SKILL.md

Install
npx -y skills add Lukk17/agent-standards --skill springboot-tdd

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.

SKILL.md

5.3 KB, ~1.3k tokens by cl100k_base, as published. Nobody here has run it

Spring Boot TDD Workflow

TDD guidance for Spring Boot services with around 90% coverage of real logic (unit + integration), and 100% where it genuinely adds value.


When to Use

  • New features or endpoints
  • Bug fixes or refactors
  • Adding data access logic or security rules

Workflow

  1. Write a failing test first (they should fail)
  2. Implement minimal code to pass
  3. Refactor with tests green
  4. Enforce coverage (JaCoCo)

Every test must satisfy FIRST: Fast (runs in milliseconds), Isolated (no dependence on other tests or shared state), Repeatable (same result on every run and every machine), Self-validating (a single pass/fail with no manual inspection), and Timely (written alongside or before the code, not bolted on afterwards). FIRST is the governing principle for this workflow.


Unit Tests (JUnit 5 + Mockito)

@ExtendWith(MockitoExtension.class)
class MarketServiceTest {
  @Mock MarketRepository repo;
  @InjectMocks MarketService service;

  @Test
  void createsMarket() {
    // Given
    CreateMarketRequest req = new CreateMarketRequest("name", "desc", Instant.now(), List.of("cat"));
    when(repo.save(any())).thenAnswer(inv -> inv.getArgument(0));

    // When
    Market result = service.create(req);

    // Then
    assertThat(result.name()).isEqualTo("name");
    verify(repo).save(any());
  }

  @Test
  void create_whenRepositoryFails_propagatesException() {
    // Given
    CreateMarketRequest req = new CreateMarketRequest("name", "desc", Instant.now(), List.of("cat"));
    when(repo.save(any())).thenThrow(new DataAccessResourceFailureException("db down"));

    // When / Then
    assertThatThrownBy(() -> service.create(req))
        .isInstanceOf(DataAccessResourceFailureException.class);
    verify(repo).save(any());
  }

  @Test
  void create_withEmptyCategories_stillCreatesMarket() {
    // Given
    CreateMarketRequest req = new CreateMarketRequest("name", "desc", Instant.now(), List.of());
    when(repo.save(any())).thenAnswer(inv -> inv.getArgument(0));

    // When
    Market result = service.create(req);

    // Then
    assertThat(result.categories()).isEmpty();
  }
}

Patterns:

  • Given / When / Then section comments in every test body
  • Cover the happy path plus error and edge cases (failures, empty inputs, boundaries)
  • Avoid partial mocks; prefer explicit stubbing
  • Use @ParameterizedTest for variants

Web Layer Tests (MockMvc)

@WebMvcTest(MarketController.class)
class MarketControllerTest {
  @Autowired MockMvc mockMvc;
  @MockitoBean MarketService marketService;

  @Test
  void returnsMarkets() throws Exception {
    // Given
    when(marketService.list(any())).thenReturn(Page.empty());

    // When / Then
    mockMvc.perform(get("/api/markets"))
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.content").isArray());
  }
}

Use @MockitoBean for mocking Spring beans on Boot 3.4 and newer; the older @MockBean is deprecated. The sibling springboot-verification skill must use the same annotation, so keep the two in sync.


Integration Tests (SpringBootTest)

@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
class MarketIntegrationTest {
  @Autowired MockMvc mockMvc;

  @Test
  void createsMarket() throws Exception {
    mockMvc.perform(post("/api/markets")
        .contentType(MediaType.APPLICATION_JSON)
        .content("""
          {"name":"Test","description":"Desc","endDate":"2030-01-01T00:00:00Z","categories":["general"]}
        """))
      .andExpect(status().isCreated());
  }
}

Persistence Tests (DataJpaTest)

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Import(TestContainersConfig.class)
class MarketRepositoryTest {
  @Autowired MarketRepository repo;

  @Test
  void savesAndFinds() {
    MarketEntity entity = new MarketEntity();
    entity.setName("Test");
    repo.save(entity);

    Optional<MarketEntity> found = repo.findByName("Test");
    assertThat(found).isPresent();
  }
}

Testcontainers

  • Use reusable containers for Postgres/Redis to mirror production
  • Wire via @DynamicPropertySource to inject JDBC URLs into Spring context

Coverage (JaCoCo)

Maven snippet:

<plugin>
  <groupId>org.jacoco</groupId>
  <artifactId>jacoco-maven-plugin</artifactId>
  <version>0.8.14</version>
  <executions>
    <execution>
      <goals><goal>prepare-agent</goal></goals>
    </execution>
    <execution>
      <id>report</id>
      <phase>verify</phase>
      <goals><goal>report</goal></goals>
    </execution>
  </executions>
</plugin>

Assertions

  • Prefer AssertJ (assertThat) for readability
  • For JSON responses, use jsonPath
  • For exceptions: assertThatThrownBy(...)

Test Data Builders

class MarketBuilder {
  private String name = "Test";
  MarketBuilder withName(String name) { this.name = name; return this; }
  Market build() { return new Market(null, name, MarketStatus.ACTIVE); }
}

CI Commands

  • Maven: mvn -T 4 test or mvn verify
  • Gradle: ./gradlew test jacocoTestReport

Remember: Keep tests fast, isolated, and deterministic. Test behavior, not implementation details.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Gives 3 of the 12 instructions most tdd skills give in ~1.3k tokens

Counted across 439 of the 443 authors here whose files we hold, read 2026-08-07

  • Write minimal code to pass the testhere, and in 304 of 439, across 222 files
  • Write a failing test firsthere, and in 174 of 439, across 111 files
  • Refactor code only after tests passin 172 of 439, across 102 files
  • Watch the test fail before writing codein 145 of 439, across 97 files
  • Test one behavior per testin 108 of 439, across 46 files
  • Refactor code while keeping tests greenhere, and in 100 of 439, across 88 files
  • Delete code written before testsin 99 of 439, across 55 files
  • Run tests after each refactor stepin 88 of 439, across 57 files
  • Confirm the test fails for the right reasonin 66 of 439, across 62 files
  • Use real code instead of mocks unless unavoidablein 60 of 439, across 17 files
  • Reproduce bugs with a test before fixingin 53 of 439, across 36 files
  • Write tests before implementationin 51 of 439, across 43 files

Said here and by no other author read

  • use mockitobean for mocking beans
  • use reusable testcontainers for databases
  • enforce coverage with jacoco

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 326,750. 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.