Clean Code: 단위 테스트

jiffydev·2021년 6월 5일
0

Clean Code

목록 보기
8/13

테스트 코드는 실제 코드만큼, 어쩌면 실제 코드보다 더 중요할 수 있다.
테스트 코드는 실제 코드의 유연성, 유지보수성, 재사용성을 보존 강화한다.
테스트 코드도 클린하게 유지해야 실제 코드가 망가지지 않는다.

1. TDD 법칙 세 가지

  • 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다.

  • 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다.

  • 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다.

이를 통해 테스트 코드와 실제 코드가 함께 나오고, 실제 코드를 전부 테스트할 수 있게 된다.

2. 깨끗한 테스트 코드 유지

지저분한 테스트 코드를 만드는 것은 테스트를 하지 않는 것만 못하다.
실제 코드처럼 테스트 코드도 깨끗하게 짜야 한다.

  • 테스트는 유연성, 유지보수성, 재사용성 제공
    깨끗한 테스트 코드가 있으면 변경이 쉬워지므로, 코드 구조도 쉽게 개선할 수 있게 된다.

3. 깨끗한 테스트 코드

깨끗한 테스트 코드는 깨끗한 실제 코드와 마찬가지로 가독성이 최우선이다.
최소한의 표현으로 많은 것을 나타내야 한다.

// BAD
public void testGetPageHierarchyAsXml() trhows Exception 
{
  crawler.addPage(root, PathParser.parse("PageOne"));
  crawler.addPage(root, PathParser.parse("PageOne.ChildOne"));
  crawler.addPage(root, PathParser.parse("PageTwo"));
  
  request.setResource("root");
  request.addInput("type", "pages");
  Responder responder = new SerializedPageResponder();
  SimpleResponse response = 
    (SimpleResponse) responder.makeResponse(
      new FitNesseContext(root), request);
  String xml = response.getContent();
  
  assertEquals("text/xml", response.getContentType());
  assertSubString("<name>PageOne</name>", xml);
  assertSubString("<name>PageTwo</name>", xml);
  assertSubString("<name>ChildOne</name>", xml);
}

위 예시는 중복된 코드가 많고 자질구레한 사항이 많아 표현력이 떨어지므로 아래와 같이 수정하는 것이 좋다.

// GOOD
public void testGetPageHierarchyAsXml() trhows Exception {
  // BUILD
  makePages("PageOne", "PageOne.ChildOne", "PageTwo");
  
  // OPERATE
  submitRequest("root", "type:pages");
  
  // CHECK
  assertResponseIsXML();
  assertResponseContains(
    "<name>PageOne</name>", "<name>PageTwo</name>", "<name>ChildOne</name>");
}

수정된 코드는 BUILD-OPERATE-CHECK 패턴을 사용해 수행하는 작업을 명확히 나누었다. 또한 잡다한 코드를 없애, 정말 필요한 자료 유형과 함수만 사용하고 있다.

  • 도메인 특화된 언어
    수정된 코드에서는 도메인 특화된 언어(DSL)을 통해 API 위에 함수와 유틸리티를 구현한 후 그 함수와 유틸리티를 사용함으로써 테스트 코드를 짜기도, 읽기도 쉽게 만들었다.

  • 이중 표준
    테스트 코드는 실제 코드만큼이나 깔끔해야 하지만, 효율성의 측면에서는 실제 코드만큼 효율적일 필요는 없다.

4. 테스트 당 assert 하나

assert문이 하나이면 코드를 이해하기 쉽고 빠르다.
다만 이를 위해 테스트를 쪼개야 할 경우 중복되는 코드가 많아진다는 단점이 있다.
이 때는 TEMPLATE METHOD 패턴을 사용해 중복을 제거할 수 있다.
'테스트 당 assert 하나' 원칙은 절대적인 것은 아니지만 assert문은 최대한 줄이는 것이 바람직하다.

  • 테스트 당 개념 하나
    여러 개념을 연속으로 테스트하는 함수는 피해야 한다.

5. F.I.R.S.T

  • Fast: 테스트는 빠르게 동작하여 자주 돌릴 수 있어야 한다. 자주 돌려야 초반에 문제를 발견하기 쉽다.

  • Independent: 각 테스트는 독립적이어야 한다. 테스트가 서로 의존하면 하나가 실패할 때 나머지도 잇따라 실패하므로 원인을 진단하기 어려워진다.

  • Repeatable: 테스트는 어떤 환경에서도 반복 가능해야 한다. (네트워크가 없는 환경에서도)

  • Self-validating: 테스트는 bool 값으로 결과를 내야 한다. 성공 or 실패.

  • Timely: 테스트는 적시에 작성한다. 여기서 적시는 실제 코드를 구현하기 직전이다.

profile
잘 & 열심히 살고싶은 개발자

0개의 댓글