8. 테스트 주도 개발
Test-Driven Development
•테스트를먼저만들고
테스트를통과하는구현을작성
• 테스트코드부터시작
• 테스트없이제품코드작성하지않음
•테스트를통과할만큼의코드만작성
• 불필요한코드작성최소화
• 과도한설계방지
8TDD 발담그기@공감세미나
9. 야구 게임 예
•야구게임규칙
• 숫자3개를맞추면이김
• 각숫자는겹치지않음
• 예측한숫자가존재할때
• 위치가같으면스트라이크
• 위치가다르면볼
9TDD 발담그기@공감세미나
10. 야구 게임 예
•정답이371일때
• 예측한숫자가582이면0볼0스트라이크
• 예측한숫자가371이면3스트라이크
• 예측한숫자가389이면1스트라이크
• 예측한숫자가317이면2볼1스트라이크
10TDD 발담그기@공감세미나
11. 야구 게임 예: 테스트 코드로 시작
@Test
publicvoidnomatch(){
//정답이479인게임에서
Gamegame=newGame(479);
//123을예측하면
Scores=game.guess(123);
//0스트라이크,0볼
assertThat(s.strikes()).isEqualTo(0);
assertThat(s.balls()).isEqualTo(0);
}
11TDD 발담그기@공감세미나
29. 테스트 코드의 전형적인 구성
•세개로구성
• 상황/조건(Given)
• 기능실행(When)
• 결과(Then)
• 검증,확인
@Test
publicvoidnomatch(){
//Given:정답이479일때
Gamegame=newGame(479);
//When:123을예측하면
Scores=game.guess(123);
//Then:0스트라이크,0볼
assertThat(s.strikes()).isEqualTo(0);
assertThat(s.balls()).isEqualTo(0);
}
29TDD 발담그기@공감세미나
30. 테스트 코드 작성 예
// Given: 비정상 계좌
givenAbnormalAccount("111222333444");
// When: 비정상 계좌로 자동 이체를 신청
ApplyReq applyReq = ApplyReq.builder().
.accountNum("111222333444").userId("myuser")
.socialNum("060101").build();
ApplyResult rst = autoDebitSvc.applyAutoDebit(applyReq);
// Then: 자동 이체 신청에 실패해야 함
assertThat(rst.isSuccess()).isFalse();
assertThat(rst.getFailCause())
.isEqualTo(FailCause.ABNORMAL_ACCOUNT);
30TDD 발담그기@공감세미나
31. // Given: 비정상 계좌
givenAbnormalAccount("111222333444");
// When: 비정상 계좌로 자동 이체를 신청
ApplyReq applyReq = ApplyReq.builder().
.accountNum("111222333444")
.userId("myuser")
.socialNum("060101").build();
ApplyResult rst = autoDebitSvc.applyAutoDebit(applyReq);
// Then: 자동 이체 신청에 실패해야 함
assertThat(rst.isSuccess()).isFalse();
assertThat(rst.getFailCause())
.isEqualTo(FailCause.ABNORMAL_ACCOUNT);
테스트 코드 작성 설계 고민 필요
테스트 대상의
타입 이름과
메서드 이름 고민
기능에 전달할
입력 데이터 고민
결과를 검증하려면
기능의 응답 방식 고민
계좌 비정상 여부를 어떻게 지정
31TDD 발담그기@공감세미나
32. 테스트 코드 작성 설계 고민 필요
은행에 통지한다는 걸
어떻게 확인할 수 있나
@Test
publicvoid정상계좌면_신청성공_은행통지(){
//Given:정상계좌
givenNormalAccount("111222333444");
// When: 정상 계좌로 자동 이체를 신청
ApplyReq applyReq = ApplyReq.builder().
.accountNum("111222333444")
.userId("myuser")
.socialNum("060101").build();
ApplyResult rst = autoDebitSvc.applyAutoDebit(applyReq);
//Then:은행에자동이체계좌통지해야함
bankShouldBeNotified("111222333444");
}
32TDD 발담그기@공감세미나
33. 테스트 코드와 협업 객체 도출
상황/조건에서
테스트 대상의
협업 객체 도출
가능성 검토
// Given: 비정상 계좌
givenAbnormalAccount("111222333444");
// When: 비정상 계좌로 자동 이체를 신청
ApplyReqapplyReq = ApplyReq.builder().
.accountNum("111222333444").userId("myuser")
.socialNum("060101").build();
ApplyResultrst = autoDebitSvc.applyAutoDebit(applyReq);
// Then: 자동 이체 신청에 실패해야 함
assertThat(rst.isSuccess()).isFalse();
assertThat(rst.getFailCause())
.isEqualTo(FailCause.ABNORMAL_ACCOUNT);
33TDD 발담그기@공감세미나
34. // Given: 비정상 계좌
givenAbnormalAccount("111222333444");
// When: 비정상 계좌로 자동 이체를 신청
ApplyReqapplyReq = ApplyReq.builder().
.accountNum("111222333444").userId("myuser")
.socialNum("060101").build();
ApplyResultrst = autoDebitSvc.applyAutoDebit(applyReq);
// Then: 자동 이체 신청에 실패해야 함
assertThat(rst.isSuccess()).isFalse();
assertThat(rst.getFailCause())
.isEqualTo(FailCause.ABNORMAL_ACCOUNT);
협업 객체를 위한 타입 도출
AutoDebitService
AccountValidator
그 시점에 적당해 보이는 용어 사용
34TDD 발담그기@공감세미나
37. 협업 객체는 일단 대역(double)으로 대치
당장은 테스트 통과가 우선
privateAutoDebitServiceautoDebitSvc=newAutoDebitService();
privateFakeAccountValidatorfakeValidator=newFakeAccountValidator();
@Before
publicvoidsetup(){
autoDebitSvc.setAccountValidator(fakeValidator);
}
@Test
publicvoid비정상계좌는_자동이체신청_실패(){
//Given:비정상계좌
givenAbnormalAccount("111222333444");
//When:비정상계좌로자동이체를신청
ApplyReqapplyReq=ApplyReq.builder().
.accountNum("111222333444").userId("myuser")
.socialNum("060101").build();
ApplyResultrst=autoDebitSvc.applyAutoDebit(applyReq);
//Then:자동이체신청에실패
assertThat(rst.isSuccess()).isFalse();
assertThat(rst.getFailCause())
.isEqualTo(FailCause.ABNORMAL_ACCOUNT);
}
여기서 테스트하고 싶은 것은?
자동이체신청 기능 자체임
계좌를 검증하는 기능은 아님!
테스트 대상이 아니면
협업 객체인지 고민
37TDD 발담그기@공감세미나