[테스트 주도 개발] 1장_다중 통화를 지원하는 Money 객체

테스트 주도 개발의 리듬은 다음과 같다.

  1. 재빨리 테스트 하나 추가
  2. 모든 테스트 실행하고 새로 추가한 것이 실패한지 확인
  3. 코드를 조금 변경
  4. 모든 테스트 실행하고 전부 성공하는지 확인
  5. 리팩토링으로 중복 제거

어떤 테스트들이 있어야 보고서에 제대로 계산되도록 하는 코드가 완성됐다고 확신할 수 있을까 ?

  1. 통화가 다른 두 금액을 더해서 주어진 환율에 맞게 변환 금액을 결과로 얻을 수 있어야한다.
  2. 어떤 금액을 어떤 수에 곱한 금액을 결과로 얻을 수 있어야한다.

앞으로 어떤 일을 해야하는지 알려주고, 하는 일에 집중할 수 있게 하고, 언제 일이 끝나는지 알려 줄 수 있도록 할 일 목록을 만든다. 작업이 끝난 항목에는 줄을 긋는다.
할일 목록에서 볼 수 있듯이 곱하기를 먼저 다룬다. 작은 것부터 시작한다.

1
2
3
4
5
public void testMultiplication() {
Dollar five = new Dollar(5);
five.times(2);
AssertionErrors.assertEquals(10, five.amount);
}

위 테스트는 아직 컴파일조차 되지 않는다. 실행은 안되더라도, 컴파일만은 되도록 만들고 싶다. 네 개의 컴파일 에러가 있다.

  1. Dollar 클래스가 없음
  2. 생성자가 없음
  3. times(int) 메서드가 없음
  4. amount 필드가 없음
1
2
3
4
5
6
7
8
9
10
11
class Dollar {
int amount;

Dollar(int amount) {

}

void times(int multiplier){

}
}

위 코드에서 times(int multiplier) 는 stub 구현이다. 이 메서드를 호출하는 코드가 컴파일 될 수 있도록 껍데기만 만들어두는 것을 의미한다.
테스트를 다시 실행해보자. 실패한다. 테스팅 프레임워크가 결과로 10이 나와야 하는데 0이 나왔다는 것을 알려준다.

1
2
3
4
class Dollar {
int amount = 10;
...
}

이제 다시 실행해보면, 초록 막대가 나온다. 이제 중복을 제거할 차례이다.

“의존성과 중복”

의존성이 문제 그 자체라면, 중복은 문제의 징후다.

만약 특정 데이터베이스 벤더가 제공하는 세세한 기능들이 코드 곳곳에서 사용되고 있으면 다른 벤더 제품으로 변경할 때 해당 벤더에 의존성을 갖고 있다는 것을 알게 된다. 즉, 코드를 변경하지 않고 벤더를 바꿀 수 없다.

중복의 흔한 예는 로직의 중복이다. 중복된 로직을 하나로 끄집어내는 일엔 객체를 이용하는 것이 최고다.

다음 테스트로 진행하기 전에 중복을 제거하면, 다음 테스트도 통과되게 만들 가능성을 최대화한다.

1
2
3
4
5
6
7
8
9
10
class Dollar {
int amount;

Dollar(int amount) {
}

void times(int multiplier){
amount = 5 * 2;
}
}

테스트는 여전히 통과한다.

1
2
3
4
5
6
7
8
9
10
11
class Dollar {
int amount;

Dollar(int amount) {
this.amount = amount;
}

void times(int multiplier) {
amount *= multiplier;
}
}

이제 첫번째 테스트를 완료했다. 다음 장에서는 Dollar 부작용에 대한 작업을 한다.


테스트 주도 개발 <켄트 벡>

Comments