TDD(Test Driven Development) 애자일과 TDD 덕분에 단위 테스트를 자동화하는 프로그래머들이 많아졌다.
이상적인 소스 패키지는 모든 테스트 코드와 소스 코드를 같이 묶은 패키지
TDD 법치 세가지
TDD는 실제 코드를 짜기 전에 단위 테스트부터 짜라고 요구한다.
세 가지 법칙
- 첫째, 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다
- 둘째, 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다
- 셋째, 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다
이렇게 일하면 매일 수십 개, 매달 수백 개, 매년 수천 개에 달하는 테스트 케이스가 나온다.
결국에는 사실상 전부 테스트하는 테스트 케이스가 나온다.
깨끗한 테스트 코드 유지하기
실제 코드와 동일한 품질 기준을 가진 테스트 코드가 아니라 빨리 만들어낸 테스트 코드는 결국 테스트 실패로 이어진다.
테스트 코드는 이류 시민이 아니다. 실제 코드 못지 않게 깨끗하게 짜야 한다.
테스트는 유연성, 유지보수성, 재사용성을 제공한다
코드에 유연성, 유지보수성, 재사용성을 제공하는 버팀목이 바로 단위 테스트다. 이유는 단순하다.
테스트 케이스가 있으면 변경이 두렵지 않다. 테스트 케이스가 없다면 모든 변경이 잠정적인 버그다. 따라서 테스트 케이스가 없다면 개발자는 변경을 주저한다. 버그가 숨어들까 두렵기 때문이다.
하지만 테스트 케이스가 있다면 두렵지 않다. 테스트 커버리지가 높을 수록 공포는 줄어든다.
깨끗한 테스트 코드
깨끗한 코드의 조건 가독성, 명료성, 풍부한 표현력
BUILD-OPERATE-CHECK패턴
- 첫 부분은 테스트 자료를 만든다.
- 두 번째 부분은 테스트 자료를 조작한다.
- 세 번째 부분은 조작한 결과가 올바른지 확인한다
이중 표준
테스트 환경 표준과 실제 코드 표준은 확실히 다르다.
단순하고, 간결하고, 표현력이 풍부해야하는 것은 동일하지만 테스트 환경은 반드시 코드가 효율적일 필요는 없다.(성능)
이것이 이중표준의 본질이다. 실제 환경에서는 절대로 안 되지만 테스트 환경에서는 문제없는 방식이 있다.
대게 메모리, CPU 효율은효율은 코드의 깨끗함과는 철저히 무관하다.
테스트 당 assert 하나
JUnit으로 테스트 코드를 짤 때는 함수마다 assert문을 단 하나만 사용해야 한다는 주장이 있다.
가혹한 규칙이지만 확실한 장점이 있다.
이때 함수 작성 시 함수 이름은 given - when - then 관례를 주로 사용한다.
다만 이렇게 분리하면 필연적으로 중복 코드가 많아진다.
TEMPLATE METHOD 패턴을 사용하면 중복을 제거할 수 있다. given/when부분을 부모 클래스로 두고 then 부분은 상속을 받은 자식 클래스에 두면 된다.
혹은 완전히 독자적인 테스트 클래스를 만들어 @Before함수에 given/when 부분을 넣고 @Test 함수에만 then부분을 넣어도 된다.
하지만 결국 모두가 배보다 배꼽이 더 크다. 이것저것 감안하다보면 assert문을 여럿 사용하는 편이 좋다
단 이것이 단일 assert문 규칙을 부정하는게 아니다. 최대한 지킬려고 하되 여럿 사용하게된다면 최대한 assert 문 개수를 줄이는 것이 좋다.
테스트 당 개념 하나
사실 "함수당 assert문 하나"라는 규칙보다 "테스트 함수마다 한 개념만 테스트하라" 가 더 적절한 규칙 같다.
여러 잡다한 개념을 연속으로 테스트 하는 긴 함수는 피한다.
테스트 코드를 보면 assert가 여럿 사용하는 것이 문제가 아니라 한 테스트 당 여러 개념을 테스트 한다는 게 사실 핵심 문제이다
따라서 가장 좋은 규칙은 개념 당 assert문 수를 최소로 줄이면서 테스트 함수 하나는 개념 하나만 테스트
F.I.R.S.T.
깨끗한 테스트는 다음 다섯 가지 규칙을 따른다.
- Fast 빠르게
테스트는 빨라야 한다.
느리면 자주 돌릴 엄두를 못낸다.
자주 못돌리면 초반에 문제를 찾기 힘들다.
결국 코드 품질을 망치게 된다
- Independent 독립적으로
각 테스트는 서로 의존하면 안된다.
한 테스트가 다음 테스트가 실행될 환경을 준비해서는 안된다.
각 테스트는 독립적으로 어떤 순서로 실행해도 괜찮아야 한다.
테스트가 서로 의존하면 하나가 실패할 때 나머지도 잇달아 실패하므로 원인 진단이 어려워지며 후반 테스트가 찾아내야 할 결함이 숨겨진다.
- Repeatable 반복 가능하게
테스트는 어떤 환경에도 반복이 가능해야한다.
실제 환경, QA 환경, 네트워크가 연결되지 않은 환경….
테스트가 돌아가지 않는 환경이 하나라도 있다면 테스트가 실패한 이유를 댈 변명이 생긴다.
- Self-Vaildationg 자가 검증하는
테스트는 boolean 값으로 결과를 내야 한다.
즉, 성공아니면 실패뿐이다. 따라서 결과를 로그 파일을 남겨서 실패인지 성공인지 비교하게 만들어서도 안된다. 로그를 비교하는 순간 주관이 들어가게 된다. 또한 지루한 수작업 평가가 필요하다
- Timely 적시에
테스트는 적시에 작성해야 한다.
단위 테스트는 테스트하려는 실제 코드를 구현하기 직전에 구현한다.
실제 코드를 구현한 다음에 테스트 코드를 만들면 실제 코드가 테스트하기 어렵다는 사실을 발견할지도 모른다. 또한 테스트가 불가능하도록 실제 코드를 설계할지도 모른다.
결론
테스트 코드는 실제 코드만큼이나 프로젝트 건강에 중요하다
테스트 코드는 실제 코드의 유연성, 유지보수성, 재사용성을 보존하고 강화한다.
테스트 코드를 지속적으로 깨끗하게 관리하고 표현력을 높이고 간결하게 정리하자
테스트 APU를 구현해 도메인 특화 언어 DSL를 만들자. 그러면 그만큼 테스트 코드를 짜기가 쉬워진다.
테스트 코드를 방치하면 실제 코드도 망가진다.
'IT책, 강의 > 클린코드(Clean Code)' 카테고리의 다른 글
11장 시스템 (0) | 2022.11.01 |
---|---|
10장 클래스 (0) | 2022.10.26 |
8장 경계 (0) | 2022.10.18 |
7장 오류 처리 (0) | 2022.10.12 |
6장 객체와 자료 구조 (1) | 2022.10.06 |