<< All versions
Skill v1.0.0
currentLLM-judged scan90/100kuaamu/omnihive/springboot-tdd
──Details
PublishedOctober 23, 2026 at 07:32 AM
Content Hashsha256:f0696338cd733bc2...
Git SHA74c6cdf13943
──Files
Files (1 file, 3.7 KB)
SKILL.md3.7 KBactive
SKILL.md · 159 lines · 3.7 KB
version: "1.0.0" name: springboot-tdd description: Test-driven development for Spring Boot using JUnit 5, Mockito, MockMvc, Testcontainers, and JaCoCo. Use when adding features, fixing bugs, or refactoring.
Spring Boot TDD Workflow
TDD guidance for Spring Boot services with 80%+ coverage (unit + integration).
When to Use
- New features or endpoints
- Bug fixes or refactors
- Adding data access logic or security rules
Workflow
1) Write tests first (they should fail) 2) Implement minimal code to pass 3) Refactor with tests green 4) Enforce coverage (JaCoCo)
Unit Tests (JUnit 5 + Mockito)
java
@ExtendWith(MockitoExtension.class)class MarketServiceTest {@Mock MarketRepository repo;@InjectMocks MarketService service;@Testvoid createsMarket() {CreateMarketRequest req = new CreateMarketRequest("name", "desc", Instant.now(), List.of("cat"));when(repo.save(any())).thenAnswer(inv -> inv.getArgument(0));Market result = service.create(req);assertThat(result.name()).isEqualTo("name");verify(repo).save(any());}}
Patterns:
- Arrange-Act-Assert
- Avoid partial mocks; prefer explicit stubbing
- Use
@ParameterizedTestfor variants
Web Layer Tests (MockMvc)
java
@WebMvcTest(MarketController.class)class MarketControllerTest {@Autowired MockMvc mockMvc;@MockBean MarketService marketService;@Testvoid returnsMarkets() throws Exception {when(marketService.list(any())).thenReturn(Page.empty());mockMvc.perform(get("/api/markets")).andExpect(status().isOk()).andExpect(jsonPath("$.content").isArray());}}
Integration Tests (SpringBootTest)
java
@SpringBootTest@AutoConfigureMockMvc@ActiveProfiles("test")class MarketIntegrationTest {@Autowired MockMvc mockMvc;@Testvoid 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)
java
@DataJpaTest@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)@Import(TestContainersConfig.class)class MarketRepositoryTest {@Autowired MarketRepository repo;@Testvoid 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
@DynamicPropertySourceto inject JDBC URLs into Spring context
Coverage (JaCoCo)
Maven snippet:
xml
<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
java
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 testormvn verify - Gradle:
./gradlew test jacocoTestReport
Remember: Keep tests fast, isolated, and deterministic. Test behavior, not implementation details.