들어가며.
테스트 주도 개발에는 단순한 두가지 규칙만을 따른다
- 오직 자동화된 테스트가 실패할 경우에만 새로운 코드를 작성한다.
- 중복을 제거한다.
위의 규칙에 의한 프로그래밍 순서는 다음과 같다.
- 빨강- 실패하는 작은 테스트를 작성한다.
- 초록- 어찌되었든지간에 테스트를 통과하게 만든다.
- 리팩토링- 일단 테스트를 통과하면서 생겨났던 모든 중복을 제거한다.
왜 이런식으로 작업해야할까? 왜 테스트를 위한 추가 작업을 해야만 하는가?
-> 불확실함 보다는 일단 구체적으로 시작해보자.
-> 새로운 설계 결정을 한번에 하나씩 도입하기 위해.
목표는 작동하는 깔끔한 코드를 만드는 것이다.
1장 다중 통화를 지원하는 Money 객체
앞으로 어떤일을 해야하는지 알려주고
지금하는일에 집중할 수 있도록 도와주며
언제 일이 다 끝나는지 알려줄 수 있는 할일 목록을 작성하자.
다른 테스트가 생가가나면 목록에 새롭게 항목을 추가한다.
마치 트렐로 카드 목록과 비슷하다.
$5 + 10CHF = $10 (환율이 2:1일 경우) $5 x 2 = $10 |
객체를 만들면서 시작하는게 아니라 테스트를 먼저 만들어야 한다.
첫번째 테스트는 복잡해 보이므로 두번째 것부터 시작.
public void testMultiplication() {
Dollar five = new Dollar(5);
five.times(2);
assertEquals(10, five.amount);
}
-> 할일목록 업데이트
$5 + 10CHF = $10(환율이 2:1일 경우) $5 x 2 = $10 amount를 private으로 만들기 Dollar 부작용(side effect)? Money 반올림? |
-> 컴파일만 되게 만들어보자
네개의 컴파일 에러
- Dollar 클래스가 없음
- 생성자가 없음
- times(int) 메서드가 없음
- amount 필드가 없음
테스트는 실패하였다.
-> 일단 이 테스트를 통과시키고 나머지 테스트도 통과하도록 할것이다.
테스트 주기는 다음과 같다.
- 작은 테스트를 하나 추가한다.
- 모든 테스트를 실행해서 테스트가 실패하는 것을 확인하다.
- 조금 수정한다.
- 모든 테스트를 실행해서 테스트가 성공하는 것을 확인한다.
- 중복을 제거하기 위해 리팩토링을 한다.
-> 이제 중복을 제거할 것이다.
TDD의 핵심을 작은 단계를 밟아가야 한다는 것이다.
- 작업해야할 테스트 목록
- 오퍼레이션이 외부에서 어떻게 보이길 원하는지 코드로 표현
- JUnit
- 스텁구현을 통해 테스트 컴파일
- 일단 테스크 통과시킴
- 코드에서 상수를 변수로 변경. 점진적으로 일반화
- 새로운 할일들은 할일목록에 추가하고 넘어감.
2장 타락한 객체
일반적인 TDD 주기
테스트를 작성한다. 원하는 인터페이스, 필요한 모든 요소를 포함시키자 -> 일단 실행가능하게 만든다. -> 수습하고 올바르게 만든다.
목적은 작동하는 깔끔한 코드를 얻는 것.
: 일단 작동하게 하고 나서 깔끔한 코드 문제를 해결하는 것이다.
Mock객체나 Stub 으로 일단 돌아가게 테스트를 만드는것이 이 개념을 바탕으로 만들어진 것인지?
-> Dollar객체의 값을 변하지 않게 수정하자.
- times() 객체 반환하여 해결.
$5 + 10CHF = $10(환율이 2:1일 경우)
amount를 private으로 만들기
Money 반올림? |
- 가짜로 구현하기 : 상수를 반환하게 만들고 단계적으로 상수를 변수로 바꿈
- 명백한 구현 사용하기 : 실제 구현을 입력.
-> 두가지 방법을 번갈아가며 사용.
어떤것을 할지 알때는 명백한 구현은 더해나가다 실패할 경우 가짜 구현을 적절히 섞고 올바른 코드로 리팩토링.
- 설계상의 결함으로 실패하는 테스트로 변환
- 스텁 구현으로 일단 컴파일을 통과
- 올바른 코드 구현하여 테스트 통과
구체적 사례에 의해서 실패하는 테스트를 만드는것이 좋은 코드를 구현하는 방법
3장 모두를 위한 평등
일반적으로 객체는 우리 예상대로 동작하지 않는다.
Dollar 객체처럼 객체를 값처럼 쓸 수 있는 것을 값-객체 패턴 value object pattern
-> 값 객체는 equals()를 구현해야 한다.
Dollar를 해시테이블 키로 쓸 생각이라면 equals()를 구현할 때 hashCode()를 같이 구현해야 함.
$5 + 10CHF = $10(환율이 2:1일 경우)
amount를 private으로 만들기
Money 반올림? equals() hashCode() |
-> 값 객체는 새 객체를 반환해야 함
public void testEquality() {
assertTrue(new Dollar(5).equals(new Dollar(5)));
}
//가짜로 구현
public boolean equals(Object object) {
return true;
}
유추에 의해 알수있는 삼각측량을 이용
설계를 어떻게 할지 떠오르지 않을 때 삼각측량은 문제를 조금 다른 방향에서 생각해볼 기회를 제공한다.
public vlid testEquality() {
assertTrue(new Dollar(5).equals(new Dollar(5)));
assertFalse(new Dollar(5).equals(new Dollar(6)));
}
//equality 일반화
public boolean equals(Object object) {
Dollar dollar = (Dollar) object;
return amount == dollar.amount;
}
-> 동질성 기능은 구현했으므로 Dollar와 Dollar를 직접 비교할 수 있게 됐다.
이제 amount를 private으로 만들 수 있다.
- 값 객체 가 하나의 또 다른 오퍼레이션을 암시한다는걸 알았다.
- 해당 오퍼레이션을 테스트
- 해당 오퍼레이션을 간단히 구현
- 좀 더 테스트
- 두 경우 모두 수용하도록 리팩토링
'IT Book Summary > TDD' 카테고리의 다른 글
18장-20장 xUnit (0) | 2020.03.24 |
---|---|
13-17장 (0) | 2020.03.18 |
10-12장 (0) | 2020.03.10 |
7-10장 (0) | 2020.03.09 |
4-6장 (0) | 2020.03.02 |