[ 1주차 과제 ] TDD 로 개발하기 Q&A
2025. 3. 24. 23:20ㆍ향해99 8기
TDD + Mock/Stub + 단위/통합 테스트 + 동시성 테스트
TDD란?
테스트 먼저 작성 → 기능 구현 → 리팩터링
Red → Green → Refactor
- 단위 테스트(Unit Test): 하나의 메서드(기능) 단위 검증
- 통합 테스트(Integration Test): 여러 클래스가 함께 작동하는지 확인
- 동시성 제어 테스트: 동시에 여러 요청이 들어올 때도 결과가 올바른지 확인
✅ Stub vs Mock (Test Double)
Stub vs Mock
| 반환값 설정 | 행동(호출 여부, 횟수) 검증 |
| 상태 검증 | 행동 검증 |
| "이러면 이래라" | "이렇게 불렸는가?" |
// 예시 인터페이스
interface MemberService {
fun findIds(userId: Long): List<Long>
}
Stub 예제
// 호출되면 값을 "리턴"만 해주는 더블 (행동 검증 X)
whenever(service.findIds(1L)).thenReturn(listOf(1L, 2L, 3L))
Mock 예제
verify(service).findIds(1L)
// 호출됐는지 "행동 검증" verify(service, times(1)).findIds(any())
👉 Stub: 상태(값) 검증
👉 Mock: 호출(행동) 검증
✅ 단위 테스트 (Service 단독)
class PointServiceTest {
val repository = mock<PointRepository>()
val service = PointService(repository)
@Test
fun `충전하면 포인트가 증가한다`() {
// given
whenever(repository.findById(1L)).thenReturn(Point(1L, 100))
// when
service.charge(1L, 100)
// then
verify(repository).save(Point(1L, 200))
}
}
✅ 통합 테스트 (DB까지 진짜로)
@SpringBootTest
class PointServiceIntegrationTest {
@Autowired
lateinit var service: PointService
@Autowired
lateinit var repository: PointRepository
@Test
fun `충전 후 조회하면 충전한 만큼 나온다`() {
service.charge(1L, 100)
val result = service.getPoint(1L)
assertEquals(100, result.amount)
}
}
✅ 컨트롤러 vs 서비스 역할
- Controller: "형식적인" 값 검증 (@Valid, 음수인지 등)
- Service: "비즈니스" 규칙 검증 (최대 한도, 중복 등)
// Controller
@PostMapping("/charge")
fun charge(@Valid @RequestBody req: ChargeRequest) {
service.charge(req.userId, req.amount)
}
// Service
fun charge(userId: Long, amount: Int) {
if (amount < 0) throw IllegalArgumentException("음수 불가")
// 비즈니스 로직
}
✅ 동시성 테스트 예제 (CountDownLatch)
@Test
fun `3명이 동시에 100원씩 충전하면 총 300원이 된다`() {
val threadCount = 3
val latch = CountDownLatch(threadCount)
repeat(threadCount) {
thread {
service.charge(1L, 100)
latch.countDown()
}.start()
}
latch.await()
assertEquals(300, service.getPoint(1L).amount)
}
✅ 동시성 제어 전략
| synchronized, Lock | 한 번에 하나만 접근 가능 |
| DB SELECT FOR UPDATE | 트랜잭션 단위 잠금 |
| 큐 / 이벤트 | 순차적 처리 |
| Redis Lock | 분산 환경에서 사용 |
동시에 요청했을 때, 하나만 처리해야 할지 / 전부 처리해야 할지를 명확히 정의 후 테스트
✅ 구조 정리 예시
/src/main/kotlin/point/PointService.kt /src/test/kotlin/point/PointServiceTest.kt // 단위 테스트 /src/test/kotlin/point/PointServiceIntegrationTest.kt // 통합 테스트
'향해99 8기' 카테고리의 다른 글
| [ 3주차 과제 ] 이커머스 Clean + Layered Architecture 설계 (0) | 2025.04.05 |
|---|---|
| [ 2주차 과제 ] API명세, API에러 상황 정리, API에러 상황 정의 (0) | 2025.04.03 |
| [ 2주차 과제 ] 시퀀스 다이어그램, ERD (0) | 2025.04.01 |
| [ 2주차 과제 ] 스프린트 계획, 이커머스 요구사항 분석 (0) | 2025.03.29 |
| [ 1주차 과제 ] 포인트 충전/사용에 대한 정책 (0) | 2025.03.25 |