springboot-tdd
JUnit 5, Mockito, MockMvc, Testcontainers, JaCoCo를 사용한 Spring Boot 테스트 주도 개발. 기능 추가, 버그 수정, 리팩터링에 사용한다.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
JUnit 5, Mockito, MockMvc, Testcontainers, JaCoCo를 사용한 Spring Boot 테스트 주도 개발. 기능 추가, 버그 수정, 리팩터링에 사용한다.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
새 Spring Boot 서비스를 api-gateway + auth-api 에코시스템에 연결한다. auth-api 클라이언트 등록 → Gateway 라우팅 추가 → 서비스에 econo-passport 연동 → 동작 확인까지 한 번에 처리. 다음 상황에서 반드시 이 스킬을 사용한다: - "새 서비스 Gateway에 연결해줘", "새 서비스 auth 연동" - "서비스 등록해줘", "Gateway 뒤에 붙여줘" - "/register-service" 직접 호출 - 새 Spring Boot 서비스가 추가되고 인증이 필요할 때 ARGUMENTS: 서비스명, 서비스 경로(선택), 업스트림 URL(선택) 예: "EEOS-BE /Users/mando/study/eeos/EEOS-BE/eeos"
이 스킬은 사용자가 "PR 생성해줘", "PR 만들어줘", "pull request 생성", "pr 올려줘", "/git-pr" 등을 요청할 때 호출된다. 현재 브랜치의 커밋을 원격으로 push하고, `.github/PULL_REQUEST_TEMPLATE.md`를 채워 GitHub Pull Request를 생성한다.
신규 기능을 개발할 때 정책 문서 → 코드 → 테스트 순서로 작성한다. ADR은 기술적 결정에만 사용하고, 기능 정책은 docs/features/ 에 작성한다. 다음 상황에서 반드시 이 스킬을 사용한다: - "기능 추가해줘", "기획부터 해봐", "설계해봐" - 새로운 API 엔드포인트 또는 도메인 규칙이 생길 때 - "/new-feature" 직접 호출 ARGUMENTS: 기능 이름 또는 요구사항 (없으면 대화에서 추출)
Architecture Decision Record(ADR)를 작성한다. 기술적 결정사항, 설계 선택, 트레이드오프를 문서화하여 나중에 "왜 이렇게 했지?"를 알 수 있게 한다. 다음 상황에서 반드시 이 스킬을 사용한다: - "ADR 써줘", "결정사항 문서화해줘", "이 결정 기록해줘" - 기술 방향 선택 후 ("A 대신 B 쓰기로 했어") - 설계 논의가 끝났을 때 - 나중에 이 결정이 왜 내려졌는지 설명이 필요할 것 같을 때 - "/adr" 직접 호출 ARGUMENTS: 결정 내용 또는 결정 번호 (없으면 대화에서 추출)
AI 에이전트의 액션 스페이스, 도구 정의, 관측(Observation) 포맷을 설계·최적화해 작업 완수율을 높일 때 사용한다.
로컬 개발, 컨테이너 보안, 네트워킹, 볼륨 전략, 멀티 서비스 오케스트레이션을 위한 Docker 및 Docker Compose 패턴.
| name | springboot-tdd |
| description | JUnit 5, Mockito, MockMvc, Testcontainers, JaCoCo를 사용한 Spring Boot 테스트 주도 개발. 기능 추가, 버그 수정, 리팩터링에 사용한다. |
| origin | ECC |
80% 이상 커버리지(단위 + 통합)를 갖춘 Spring Boot 서비스를 위한 TDD 가이드.
@ExtendWith(MockitoExtension.class)
class MarketServiceTest {
@Mock MarketRepository repo;
@InjectMocks MarketService service;
@Nested
@DisplayName("마켓 생성 테스트")
class CreateTest {
@Test
@DisplayName("정상적인 마켓 생성")
void createValidMarket() {
// 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());
}
}
}
패턴:
@Nested + @DisplayName으로 테스트를 한글로 그룹화@DisplayName은 한글@ParameterizedTest를 사용한다@WebMvcTest(MarketController.class)
class MarketControllerTest {
@Autowired MockMvc mockMvc;
@MockBean MarketService marketService;
@Nested
@DisplayName("마켓 목록 조회 테스트")
class ListTest {
@Test
@DisplayName("마켓 목록 정상 조회")
void listMarkets() throws Exception {
// given
when(marketService.list(any())).thenReturn(Page.empty());
// when & then
mockMvc.perform(get("/api/markets"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.content").isArray());
}
}
}
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
class MarketIntegrationTest {
@Autowired MockMvc mockMvc;
@Nested
@DisplayName("마켓 생성 통합 테스트")
class CreateIntegrationTest {
@Test
@DisplayName("정상적인 마켓 생성 요청 시 201 응답")
void createMarket() throws Exception {
// given
String requestBody = """
{"name":"Test","description":"Desc","endDate":"2030-01-01T00:00:00Z","categories":["general"]}
""";
// when & then
mockMvc.perform(post("/api/markets")
.contentType(MediaType.APPLICATION_JSON)
.content(requestBody))
.andExpect(status().isCreated());
}
}
}
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Import(TestContainersConfig.class)
class MarketRepositoryTest {
@Autowired MarketRepository repo;
@Nested
@DisplayName("마켓 저장 및 조회 테스트")
class SaveAndFindTest {
@Test
@DisplayName("저장 후 이름으로 조회")
void saveAndFindByName() {
// given
MarketEntity entity = new MarketEntity();
entity.setName("Test");
// when
repo.save(entity);
Optional<MarketEntity> found = repo.findByName("Test");
// then
assertThat(found).isPresent();
}
}
}
@DynamicPropertySource로 JDBC URL을 Spring 컨텍스트에 주입한다Maven 예시:
<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>
assertThat)를 선호한다jsonPath를 사용한다assertThatThrownBy(...)를 사용한다class MarketBuilder {
private String name = "Test";
MarketBuilder withName(String name) { this.name = name; return this; }
Market build() { return new Market(null, name, MarketStatus.ACTIVE); }
}
mvn -T 4 test 또는 mvn verify./gradlew test jacocoTestReport기억할 점: 테스트는 빠르고, 격리되어 있으며, 결정적이어야 한다. 구현 세부가 아닌 동작을 테스트한다.