[TDD] 간단한 TDD 적용 사례와 Kotest When절간 테스트 격리

구범모·2025년 2월 14일

최근 학습한 TDD를 실제로 적용하기 위해, 프로덕션 코드 작성 이전에 테스트 코드 먼저 작성해 보았다.

책에서 권장한 대로, 먼저 테스트 할 목록을 정리하였고

그 이후 예외적인 상황(이미 존재하는 email) 먼저 테스트를 진행하였다.

고민

Given("사용자는 회원가입을 할 때") {
        val dto = SignUpUserRequestDto("rnqjaah1234@gmail.com", "구범모")
        val blankNameDto = SignUpUserRequestDto("rnqjaah1234@gmail.com", "")
        val blankEmailDto = SignUpUserRequestDto("", "구범모")
        val alreadyExistsEmailDto = SignUpUserRequestDto("rnqjaah1234@gmail.com", "구범모")
        When("빈칸이 아닌 이름을 입력하면") {

            Then("회원가입에 성공하여 Response Dto를 반환한다") {
            }
        }

        When("빈칸이 아닌 이메일을 입력하면") {

        }

        When("이미 존재하는 이메일이면") {
            Then("예외가 발생한다") {
                val exception = shouldThrow<RuntimeException> {
                    signUpUserService.signUp(alreadyExistsEmailDto)
                }
            }
        }

        When("빈칸인 이름을 입력하면") {
            Then("예외가 발생한다") {

            }
        }

        When("빈칸인 이메일을 입력하면") {
            Then("예외가 발생한다")
        }
    }

Kotest의 BehaviorSpec 은 기본적으로 위와 같이 Given / When / Then을 호출한다.

나는 하나의 상황(Given) 아래에서 여러 입력 케이스에 대한 단위테스트를 진행하고 싶다.

하지만 그러려면 Given block 내에서, 여러개의 When절에서 필요한 dto, stubbing을 진행해 주어야 한다.

그렇게 되면 각 When절에서 필요하지 않은 필드가 공유되는 상황이 생긴다.

해결

Given("사용자는") {
        And("회원가입을 할 때") {
            val dto = SignUpUserRequestDto("rnqjaah1234@gmail.com", "구범모")
            
            When("빈칸이 아닌 이름을 입력하면") {
                Then("회원가입에 성공하여 Response Dto를 반환한다") {
                
                }
            }
        }
        And("회원가입을 할 때") {
            val dto = SignUpUserRequestDto("rnqjaah1234@gmail.com", "구범모")

            When("빈칸이 아닌 이메일을 입력하면") {

								Then("회원가입에 성공하여 Response Dto를 반환한다") {
                
                }

            }
        }

        And("회원가입을 할 때") {
            val alreadyExistsEmailDto = SignUpUserRequestDto("rnqjaah1234@gmail.com", "구범모")
            every { signUpUserPort.existsByEmail(any()) } returns true
            When("이미 존재하는 이메일이면") {
                Then("예외가 발생한다") {
                    shouldThrow<RuntimeException> {
                        signUpUserService.signUp(alreadyExistsEmailDto)
                    }
                }
            }
        }

        And("회원가입을 할 때") {
            val blankNameDto = SignUpUserRequestDto("rnqjaah1234@gmail.com", "")
            
            When("빈칸인 이름을 입력하면") {
                Then("예외가 발생한다") {

                }
            }
        }

        And("회원가입을 할 때") {
		        val blankEmailDto = SignUpUserRequestDto("", "구범모")
            When("빈칸인 이메일을 입력하면") {
                Then("예외가 발생한다") {

                }
            }
        }
    }

Kotest 공식문서를 참고하여, 위와 같이 Given과 When절 사이에 And절을 추가하여,

And절 block 내부에서 각 테스트에 사용할 필드(dto)와 stubbing을 진행하여 각 테스트간 필드 / stubbing을 격리하였다.

profile
우상향 하는 개발자

0개의 댓글