본문 바로가기

책/CleanCode

✨ Clean Code 9장: 단위 테스트

📌 TDD 법칙 세 가지

https://cio-wiki.org/wiki/Test_Driven_Development_(TDD)

  1. 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다.
  2. 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다.
  3. 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다.

TDD는 실제 코드를 짜기 전에 단위 테스트부터 짜라고 요구하고 있다. 이렇게 하다 보면 많은 테스트 케이스가 나오게 된다. 하지만 실제 코드와 맞먹을 정도로 테스트 코드는 방대해지며 이에 대한 관리 문제를 유발하기도 한다.

📌 테스트 코드는 깔끔하게 유지하자.

테스트 케이스의 중요성

개발자들은 코드의 유연성, 유지보수성, 재사용성에 대한 중요성을 알고 있다. 해당 단원에서는 이러한 중요성에 대한 버팀목이 단위 테스트라고 소개한다. 이유는 테스트 케이스가 있으면 변경에 두렵지 않기 때문이라 한다. 나도 이에 공감한다. 테스트 케이스가 없을 때 코드를 수정하고자 하면 다른 곳에 문제가 생길까 봐 두렵고 망설여졌다. 테스트 케이스가 있으면 이러한 두려움을 없앨 수 있다.

테스트 코드가 지저분하다면?

실제 코드를 변경하면 기존 테스트 케이스는 실패한다. 그러면 테스트 코드도 변경해야 한다. 여기서 어떤 문제가 생길 수 있을지 생각해봐야 한다. 테스트 코드가 만약 지저분하다면 어떨까? 실제 코드와 같다. 지저분하다면 변경하기가 두렵고 어려워진다. 테스트 코드도 깔끔하게 유지해야 한다는 소리이다. 실제 코드는 많은 변경이 일어나기 때문이다. 그렇게 하지 못한다면 테스트 코드의 본질을 잃어 오히려 부담이 될 수 있다.

어떻게 깔끔하게 유지해야 할까?

테스트 코드는 실제 코드만큼 단순하고, 간결하고, 표현력이 풍부해야 한다. 최소한의 표현으로 많은 것을 나타내는 것이 베스트이다. 하지만 실제 코드만큼 효율적일 필요는 없다. 실제 환경이 아니라 테스트 환경에서 돌아가는 코드이기 때문이다.

테스트는 주로 아래와 같이 세 부분으로 나눈다.

  1. [준비] 테스트 자료를 만든다.
  2. [실행] 테스트 자료를 조작한다.
  3. [검증] 조작한 결과가 올바른지 확인한다.

많은 개발자가 이미 알고 있을 수 있다. given-when-then 패턴을 떠올릴 수 있다. 혹시나 given-when-then 패턴에 익숙하지 않다면 아래 링크를 참고하면 좋을 것 같다. 해당 글에서는 [준비-실행-검증]이라고 간단하게 표현하였다. 만약 내가 서투르거나 마구잡이로 작성한다는 느낌이 든다면, 이런 식으로 구조화하는 것이 좋다고 생각한다.

 

Given-When-Then Pattern

테스트 코드 작성 표현 방법 (스프링 부트 환경에서) | 이번 글에서는, 테스트 코드 작성 시 자주 사용하는 Given-When-Then Pattern에 대해서 간략하게 소개하겠다. 별 내용 없는 글이므로, 아주 편한

brunch.co.kr

에서는 하나의 테스트에 assert 하나를 사용하는 것이 좋다고 한다. 이 부분을 읽으면서 하나의 테스트에 assert 여러 개로 검증하는 나의 코드가 떠올랐다. assert 하나로 작성하려면 결국엔 테스트를 나눠줘야 한다. 하지만 여기서 많은 중복이 발생할 수 있다. 그래서 assert 여러 개를 사용했다. 책에서는 중복을 제거하는 방법으로 TEMPLATE METHOD 패턴을 언급했다. 하지만 배보다 배꼽이 더 크기 때문에 차라리 assert 문을 여러 개를 사용하는 것이 좋다고 한다. 뭔가 모순적인 상황인 것 같다. 결국은 assert 문은 최대한 줄이며, 테스트 함수마다 한 개념만 테스트하자 라고 규칙을 정하는 것이 좋다.

📌 F.I.R.S.T

F.I.R.S.T는 깨끗한 테스트를 만들기 위한 5가지 규칙을 말한다.

F.I.R.S.T 설명
빠르게(Fast) 테스트는 빨라야 한다.
테스트는 자주 돌려야하기 때문이다.
독립적으로(Independent) 각 테스트는 의존하면 안 된다.
잇달아 실패하여 원인을 진단하기 어렵고 후반 테스트가 찾아야 할 경함이 숨겨질 수 있다.
반복가능하게(Repeatabel) 어떤 환경에서도 반복 가능해야 한다.
네트워크에 연결되어 있지 않거나 실제 환경 모두 실행할 수 있어야 한다.
자가검증하는(Self-Validating) 테스트는 부울 값으로 성공 아니면 실패로 결과를 내야 한다.
적시에(Timely) 테스트는 적시에 작성해야 한다.
단위 테스트는 테스트하려는 실제 코드를 구현하기 직전에 구현한다.

📌 결론

테스트 코드는 실제 코드만큼 중요하다.
최대한 단순하고, 간결하고, 표현력이 풍부하게 나타내라.
assert 문은 최대한 줄이고, 하나의 테스트에 한 개념만 테스트하고 있는지 물음표를 던져봐라.