클린코더스, tdd 시작하기

TDD의 원칙들

    1. 실패하는 테스트가 있을 때만 프로덕션 코드를 작성할 수 있다.
    1. 실패를 나타내는데 충분한 테스트 코드만 작성하라
    1. 실패하는 테스트가 성공할 수 있는 수준으로만 테스트 코드를 작성하라.

실패하는 테스트가 있을 때만 프로덕션 코드를 작성하라

  • “실패하는 테스트”가 다소 모호할 수 있다. 이 말은 정확하게 이야기하면 프로덕션 코드가 없는 상태에서, 그것이 있는 것처럼 코드를 작성하는 방식을 의미한다. 그러니까 프로덕션 코드를 작성하기 전에 그것이 있음을 상정하여 테스트 코드를 작성하라는 의미이다.
@Test
void printBMI(){
    BodyCheckResult checkResult = BodyCheckFactory.checkBody();
    BMICheck bmiCheck = new MansBMICheck();
    checkResult.calculateBMI(bmiCheck);
    String bmi = checkResult.getBMIResult();
}
  • 건강을 검사하는 코드를 작성하고자 마음을 먹고 위와 같이 코드를 작성했다고 가정하자. 이때 위의 클래스와 메서드는 실제 코드로 존재하지 않는다. 그러니까 IDE에서 작성하면 빨간줄로 경고창이 뜨는 상태이다.
  • 이때 코드를 실행하면 당연히 실패한다. 이러한 테스트 코드를 실패한 코드라 한다. TDD는 여기서부터 시작한다.
  • 해당 코드에 걸맞는 클래스와 메서드를 구현할 경우, 그러니까 프로덕션 코드를 작성하면, 위의 실패한 코드는 성공한 코드가 된다.
  • 실패하는 코드를 작성한 후 원칙 2, 3을 수행한다. 해당 테스트를 통과할 최소한의 코드만 작성한다. 이를 통해 필요가 없거나 복잡한 코드를 작성하지 않을 수 있다. 반대로 테스트코드에 몰두하여 중복되는 테스트 코드를 작성해서도 안된다.
  • 적절한 수준의 테스트와 적절한 수준의 프로덕션 코드만을 구현한다. 이런 균형감각을 통하여 프로덕션과 테스트 코드 양 쪽에 치우치지 않도록 한다.

red green blue과 리팩터링

  • TDD는 red - green - blue의 반복되는 과정으로 이뤄진다. 실패하는 테스트 -> 기능 구현 -> 리팩토링 -> 실패하는 테스트
  • 코드의 구현과 리팩터링은 분리해야한다. 코드가 동작하는 최소한의 수준의 코드를 작성한다. 테스트가 성공하면, 이를 회귀 테스트로 하여 리팩터링한다.
  • 리팩터링을 더 이상 할 수 없을 때 코드 작성은 종료된다.
  • 테스트코드도 코드로서 리팩터링의 대상이 된다. 읽기 쉽고 유지보수하기 쉬운 테스트코드를 작성한다.

쓸데 없고 쉬운 코드부터 테스트를 한다.

  • most simple, most interesting, degenerate case first
  • 쓸데 없고 하찮고 별거 없는 코드부터 작성한다.
  • 모든 코드에 모든 테스트 케이스를 구현하려면 쉽고 하찮은 것부터 시작해야 한다. 버그는 하찮은 부분에서 발생하고, 차후 테스트코드를 작성하려면 어렵고 복잡해진다. 구현된 코드에 테스트 코드를 작성하는 과정은 매우 지루하다. 테스트 코드를 작성하기에 좋은 코드가 아닐 수도 있다. 이 경우 많은 시간과 노동이 필요하다.
  • 처음부터 테스트 코드를 세세하고 꼼꼼하게 작성한다.

개별적이고 세세한 테스트 코드가 많아지면 프로덕션 코드는 일반적이고 범용적으로 변해간다.

  • 다양한 테스트 상황을 받아드릴 수 있기 때문에 프로덕션 코드는 가면 갈수록 범용적이고 일반적으로 변한다.
  • 세세한 부분에서 테스트 코드를 작성할 수 있기 때문에, 좋은 디자인일 가능성이 높아진다.
  • TDD가 잘 된 코드는 이러한 경향이 있다.

debug vs tdd

  • debug의 장점보다 tdd의 장점이 더 크다. 우리는 디버깅을 잘하기보다 좋은 설계를 추구해야 한다.
  • 세세하고 짜잘한 테스트가 많아질수록 디버그를 할 일이 없어진다.

그 외 TDD의 이점

테스트는 디자인에 대한 문서, 주석과 같다.

복잡한 의존성을 막는다

  • 테스트를 작성하기 어렵다는 것은 커플링, 의존성이 심하다는 것과 같다.
  • TDD로 작성하지 않은 코드는 의존성이 복잡해질 가능성이 높다. 처음부터 TDD를 통해 개발하자.

코드 작성에 자신감이 생기고 동료로부터 신뢰를 얻는다.

  • 회귀 테스트가 존재할 경우, 기능 추가 및 리팩터링 과정에서의 문제를 최소화 한다.
  • 새롭게 작성한 코드로 인하여 에러가 발생할 경우 개발자는 기획자에게 신뢰를 얻지 못한다. 자기 자신도 자신의 코드를 신뢰하기 어려워 진다. 그러므로 반드시 회귀 테스트가 필요하다.
  • 좋은 프로덕션 코드보다 좋은 테스트 코드가 우선이다.

TAD Test After Development

  • 개발 후 테스트를 작성하는 것을 신뢰할 수 없다. 대체로 이런 코드는 성공하는 케이스를 작성한다.
  • 테스트 코드 작성이 귀찮다. 낭비로 느낀다. 한 두 개의 중요한 부분에 대한 테스트 코드 작성으로 끝날 가능성이 높다.