[ TDD 법칙 세 가지 ]
첫째 법칙: 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다.
둘째 법칙: 컴파일은 실패하지 않으면서 실행히 실패하는 정도로만 단위 테스트를 작성한다.
셋째 법칙: 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다.
[ 깨끗한 테스트 코드 유지하기 ]
실제 코드가 진화하면 테스트 코드도 변해야 한다. 그런데 테스트 코드가 지저분할 수록 변경이 어려워진다. 실제 코드를 변경해 기존 테스트 케이스가 실패하기 시작하면, 지저분한 코드로 인해, 실패하는 테스트 케이스를 점점 더 통과시키기 어려워진다. 그래서 테스트 코드는 계속해서 늘어가는 부담이 되어버린다.
테스트 코드는 실제 코드 못지 않게 중요하다.
테스트 코드는 이류 시민이 아니다. 테스트 코드는 사고와 설계와 주의가 필요하다. 실제 코드 못지 않게 깨끗하게 짜야 한다.
테스트는 유연성, 유지보수성, 재사용성을 제공한다
코드에 유연성, 유지보수성, 재사용성을 제공하는 버팀목이 바로 단위 테스트 다. 테스트 케이스가 없다면 모든 변경이 잠정적인 버그다. 실제 코드를 점검하는 자동화된 단위 테스트 슈트는 설계와 아키텍처를 최대한 깨끗하게 보존하는 열쇠다. 따라서 테스트 코드가 지저분하면 코드를 변경하는 능력이 떨어지며 코드 구조를 개선하는 능력도 떨어진다. 테스트 코드가 지저분할수록 실제 코드도 지저분해진다. 결국 테스트 코드를 잃어버리고 실제 코드도 망가진다.
[ 깨끗한 테스트 코드 ]
깨끗한 테스트 코드를 만들려면? 세 가지가 필요하다. 가독성, 가독성, 가독성.
잡다하고 세세한 코드를 거의 다 없애고, 테스트 코드는 본론에 돌입해 진짜 필요한 자료 유형과 함수만 사용한다.
[ 테스트 당 assert 하나 ]
JUnit으로 테스트 코드를 짤 때는 함수마다 assert문을 단 하나만 사용해야 한다. assert 문이 단 하나인 함수는 결론이 하나라서 코드를 이해하기 쉽고 빠르다.
public void testGetPageHierarchyAsXml() throws Exception {
givenPages("PageOne", "PageOne.ChildOne", "PageTwo");
whenRequestIsIssued("root", "type:pages");
thenResponseShouldBeXML();
}
public void testGetPageHierarchyHasRightTags() throws Exception {
givenPages("PageOne", "PageOne.ChildOne", "PageTwo");
whenRequestIsIssued("root", "type:pages");
thenResponseShouldContain(
"<name>PageOne</name>", "<name>PageTwo</name>", "<name>ChildOne</name>"
);
}
함수 이름을 바꿔 given-when-then이라는 관례를 사용했다. 그러면 테스트 코드를 읽기가 쉬워진다. 불행하게도, 위에서 보듯이, 테스트를 분리하면 중복되는 코드가 많아진다.
TEMPLATE METHOD 패턴을 사용하면 중복을 제거할 수 있다. 아니면 독자적인 클래스를 만들어 @Before 함수에 given/when 부분을 넣고 @Test 함수에 then 부분을 넣어도 된다.
나는 '단일 assert 문'이라는 규칙이 훌륭한 지침이라 생각한다. 대체로 나는 단일 assert를 지원하는 해당 분야 테스트 언어를 만들려 노력한다. 하지만 때로는 주저 없이 함수 하나에 여러 assert 넣기도 한다. 단지 assert 문 개수는 최대한 줄여야 좋다는 생각이다.
[ 테스트 당 개념 하나 ]
"테스트 함수마다 한 개념만 테스트하라"는 규칙이 있다고 생각하는게 더 좋겠다. 가장 좋은 규칙은 "개념 당 assert 문 수를 최소로 줄여라"와 "테스트 함수 하나는 개념 하나만 테스트하라"라 하겠다.
[ F.I.R.S.T ]
깨끗한 테스트는 다음 다섯 가지 규칙을 따른다. 각 규칙에서 첫 글자를 따오면 FIRST가 된다.
-빠르게(Fast)
테스트는 빨라야 한다.
-독립적으로(Independent)
각 테스트는 서로 의존하면 안 된다. 한 테스트가 다음 테스트가 실행될 환경을 준비해서는 안 된다.
-반복가능하게(Repeatable)
테스트는 어떤 환경에서도 반복 가능해야 한다.
-자가검증하는(Self-Validating)
테스트는 부울(bool) 값으로 결과를 내야 한다. 성공 아니면 실패다. 통과 여부를 알려고 로그 파일을 읽게 만들어서는 안된다.
-적시에(Timely)
테스트는 적시에 작성해야 한다. 단위 테스트는 테스트하려는 실제 코드를 구현하기 직전에 구현한다.
[ 결론 ]
사실 깨긋한 테스트 코드라는 주제는 위에 주어진 것만으로 부족하다. 또한 테스트 코트는 실제 코드 만큼이나 프로젝트 건강에 중요하다. 테스트 코드는 실제 코드의 유연성, 유지보수성, 재사용성을 보존하고 강화하기 때문이다.. 그러므로 테스트 코드는 지속적으로 깨끗하게 관리하자. 표현력을 높이고 간결하게 정리하자. 테스트 API를 구현해 도메인 특화 언어(Domain Specific Language, DSL)를 만들면 그만큼 테스트 코드를 짜기가 쉬워진다.
'Reading Book > Clean Code' 카테고리의 다른 글
[Clean Code]클린코드_10_클래스 (0) | 2021.08.17 |
---|---|
[Clean Code]클린코드_8_경계 (0) | 2021.08.17 |
[Clean Code]클린코드_7_오류 처리 (0) | 2021.08.17 |
[Clean Code]클린코드_6_객체와 자료 구조 (0) | 2021.08.17 |
[Clean Code]클린코드_5_형식 맞추기 (0) | 2021.08.17 |