All Articles

클린 코드 스터디 (9): 단위 테스트

9. 단위 테스트

테스트 코드를 몰랐을 때와, 테스트 코드의 중요성을 알고 올바르게 쓰기 시작한 차이는 천양지차였습니다. 기본적인 방법은 이 책으로 배우고, 파이썬에선 어떻게 쓰이는지 스스로 찾아보았습니다. 이번 장에서는 단위 테스트가 시사하는 중요한 사실 몇가지를 살펴봅시다.

TDD 법칙 세 가지

TDD는 실제 코드를 작성하기 전 단위 테스트부터 작성하라고 요구하지요. 책에서 제시하는 세 가지 법칙을 살펴봅시다.

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

말을 풀어보면…

  1. 실제 코드는 잘 설계된 단위 테스트를 갖추고 짜야하며
  2. 그 방안은 테스트 코드 로직만 돌 정도로 짜야합니다
  3. 테스트를 다시 Pass 시키고 코드를 리팩토링하면 되니까, 우선 로직을 완성해봅시다

정도가 되겠네요. 이러면 개발과 테스트가 30초 주기로 묶인다구요?? 절대 동의할 수 없습니다ㅠㅠ

이렇게 일하면 테스트코드도 수백수천개가 나오겠지요. 그렇지만 테스트 코드가 짐이되면 어떻게 될 까요?

깨끗한 테스트 코드 유지하기

실제 코드가 진화하면 테스트 코드도 그에 따라 발맞추어야 하며, 지저분한 테스트 코드는 안하느니만 못합니다. 그런데 실제 코드를 변화시킴에 따라 더러운 테스트 코드를 바꾸기는 쉽지 않지요. 이 때 악순환이 발생합니다.

  1. 더러운 테스트코드를 고치기 두려워집니다. 테스트가 있어야 코드를 검증할테니까요.
  2. 더러운 코드는 필연적으로 더러운 코드를 낳습니다. 그러면 개발기간도 길어집니다.
  3. 하지만 테스트 suite(슈트)마저 없으면 코드를 확인할 길이 없습니다. 그러면 다시 두려워집니다…

테스트 코드 또한 실제 코드 만큼이나 중요합니다.

테스트는 유연성, 유지보수성, 재사용성을 제공합니다

테스트 코드도 유지하지 않으면 망가집니다. 이게 없으면 실제 코드를 유연하게 만들 버팀목이 사라지는 셈입니다. 따라서 실제 코드를 점검하는 Automated unit test suite은 설계와 아키텍처를 깨끗하게 보존하는 열쇠입니다. 이게 있어야 코드를 바꾸기 쉽습니다.

즉 테스트 코드를 지저분하게 두지 말고 깔끔하게 만들어야 합니다. 그렇다면 깨끗한 테스트코드는 어떻게 만들까요?

깨끗한 테스트 코드

세 가지가 필요합니다.

  • 가독성
  • 가독성
  • 가독성

테스트 코드 또한 명료하고, 단순하고, 표현력이 좋은 코드여야 합니다.

AAA(Arrange-Assert-Act) 형식1으로 테스트코드를 세 부분으로 나누는 것이 권장됩니다. 정말 필요한 것들만 명료하게 제공합니다. 잡다하고 세세한 코드는 숨깁니다.

DSL에 특화된 테스트 언어

도메인을 표현하기 위해 감싼 나만의 함수와 유틸리티로 로직을 바로 테스트하면 테스트가 정말 간결해지겠지요. 이런 API는 테스트 코드를 위한 특수한 API가 되지요.

이중 표준

테스트 코드는 가능하면 짧게, 필요하다면 “그릇된 정보를 피하라” 라고 말했던 부분을 어길 수도 있습니다. 그렇지만 테스트를 빠르게 이해하기에는 더할나위없이 쉽지요. 실제환경에서는 신경써야할 메모리, CPU 효율도 테스트 코드 작성에는 무시될 수도 있습니다.

테스트 당 assert 하나

이는 JUnit의 전통 중 하나라고 합니다. 결론이 하나니까 직관적입니다. 그런데 유사 개념을 테스트할 때의 코드 중복은 어떻게 처리할까요?

코드가 복잡해지면 TEMPLATE METHOD 패턴을 적용해봄직 합니다만, 처음부터 그럴 필요는 없을 것입니다(저라도 assert를 중복해서 쓰겠어요).

이는 지향해야 할 태도입니다. 그런데 assert를 하나만 두기엔 너무 원론적입니다. 따라서…

테스트 당 개념 하나

한 개념을 테스트하기 위한 assert는 같이 담을 수 있겠으나, 여러 개념이 테스트 메소드 안에 들어가지 않도록 하는 편이 좋겠습니다.

F.I.R.S.T.

저자는 이런 이름을 붙여서 아래 규칙을 따르기를 말합니다.

  • Fast: 테스트는 빨리 돌아야 합니다. 자주 돌 수 있게 만들어야 합니다.
  • Independent: 테스트는 독립적이어야 합니다. 테스트는 다른 테스트에 의존해서는 안됩니다. 만일 그렇게 된다면, 가면 갈 수록 원인을 찾기 힘들어집니다.
  • Repeatable: 어떤 환경에서든 반복 가능해야 합니다. 네트워크가 연결되어있지 않더라도 가능해야 합니다.
  • Self-Validating: 테스트 결과는 성공/실패 뿐이어야 합니다. 테스트 통과를 확인하기 위해 판단하지 말아야 하고 스스로가 결과를 리턴하게 해야합니다.
  • Timely: 적시에 테스트를 짜야합니다. 앞서 말한 “실제 코드” 작성 전에 짜야합니다. 그렇지 않으면 테스트 하기 어려워집니다.

결론

테스트 코드는 중요합니다. 실제 코드만큼이나 중요하니, 이를 잘 관리해야합니다. 깨끗하게 관리하기 위해 가독성과 테스트 코드의 표준을 둡시다. 그리고 도메인을 잘 표현하는 별도 로직을 작성해서 짧고 핵심만 말하는 코드를 짜봅시다.


  1. 저자의 FitNesse 프로젝트에선 BUILD-OPERATE-CHECK 패턴이라고 부릅니다. 이렇게 부르는 이유는, 저자의 프로젝트에선 빌드하고 작동시킨 후 체크하기 때문이지요.

Published Feb 10, 2023

Non scholæ sed vitæ discimus.

his/him