TDD (Test Driven Development)

27 April 2014

TDD

Test the program before you write it. Kent Beck

프로그램을 작성하기 전에 테스트를 먼저 작성하는 것. 작성하고자 하는 메소드의 정상 동작 조건을 미리 코드로 표현해놓고, 그 뒤에 실제 코드를 작성한다.

TDD의 목적

Clean code that works Ron Jeffries

잘 동작하는 깔끔한 코드.

  • works : 소프트웨어 개발에서 당연한 목표
  • clean code : 유지보수의 편의성, 가독성, 그에 따른 비용, 안전성 등을 포함

TDD의 기원

Agile 개발 방식 중 하나인 XP의 여러 실천 방식 중 하나

TDD의 진행 방식

  1. Ask: 테스트 작성을 통해 시스템에 질문한다. (pass or fail?)
  2. Response: 테스트를 통과하는 실제 코드를 작성하여 질문에 응답한다.
  3. Refine: 아이디어를 통합하고, 불필요한 것은 제거하고, 모호한 것은 명확히 하여 응답을 정제한다. (리팩토링)
  4. Repeat: 1~3을 반복.

TDD 실습

  1. 필요한 메소드, 기능이 무엇인지 리스트업한다.
  2. 메소드의 정상 동작 조건을 정하고, 이를 만족하는지 확인하는 테스트 케이스를 작성한다. 이 때 테스트 케이스를 실행해보면 당연히 실패한다. (아직 실제 코드가 구현되지 않았으니까)
  3. 실패했던 테스트 케이스를 통과할 만큼의 실제 코드를 구현하고, 테스트 케이스를 실행해 성공하는지 확인한다.
  4. 리팩토링을 한 뒤, 여전히 테스트 케이스가 성공하는지 확인한다.

참고) TDD의 핵심은 목표 이미지를 미리 세운다. -> 자동화된 테스트 케이스를 작성한다. -> 테스트 케이스를 만족시키는 로직을 작성하고 정제한다.는 것이다. Junit을 사용한다던가 assertEquals 등을 사용한다던가 하는 것은 이 과정을 보다 쉽고 효율적으로 하기 위한 부가적인 요소일 뿐이다. Junit을 사용하지 않고 System.out.println()을 사용하여 테스트를 해도 TDD라 불릴 수 있다.

TDD의 장점

  1. 개발의 방향을 잃지 않게 유지해준다.
    • 현재 어떤 기능을 개발하고 있고, 어디까지 와 있고, 남은 단계는 무엇인지 항상 살펴볼 수 있는 나침반 역할을 해준다.
  2. 품질 높은 소프트웨어 모듈 보유
    • 필요한 만큼 테스트를 거쳤으므로 품질이 검증된 모듈을 갖게 된다.
  3. 자동화된 단위 테스트 케이스를 갖게 된다.
    • TDD의 output으로 나오는 자동화된 단위 테스트 케이스들은, 개발자가 필요시 언제든지 수행해볼 수 있다. 현재까지 작성된 시스템의 이상 유무를 바로 확인해볼 수 있고, 코드 변경시 회귀 테스트에 대한 부담도 줄어든다.
  4. 명세화된 문서 및 communication 수단이 된다.
  5. 설계 개선
    • 테스트 케이스 작성 시 Class, Interface, 접근제어자, naming, argument 등 다양한 설계 요소에 대해 미리 고민하게 된다.
    • 테스트하기 어려운 코드는 객체 설계 원리 중 기본에 해당하는 원칙들이 잘못 적용되었거나 충분히 고려되지 않았을 가능성이 높다. TDD를 진행하면서 테스트가 가능하도록 설계 구조를 고민하다 보면 자연스럽계 설계를 개선하게 된다.
    • 미리 고민해보고 작성하는 것과 작성하면서 그때그때 추가하는 것은, 모듈의 응집도와 의존성에 있어서 적지 않은 차이를 만들어낸다.
  6. 보다 자주 성공한다.
    • 매 주기가 짧아지며, 녹색 막대를 자주 볼 수 있고, 그 때마다 목표를 미뤘다는 성취감을 느낄 수 있다.

Robert C. Martin의 TDD 원칙

  1. 실패하는 테스트를 작성하기 전에는 절대로 제품 코드를 작성하지 않는다.
  2. 실패하는 테스트 코드를 한 번에 하나 이상 작성하지 않는다.
  3. 현재 실패하고 있는 테스트를 통과하기에 충분한 정도를 넘어서는 제품 코드를 작성하지 않는다.

이 세 가지 법칙을 따르면 TDD 개발의 주기가 30초~1분사이로 유지된다고 한다.

단위 테스트 케이스 작성 가이드

  • 결과가 옳은가?
  • 모든 경계조건이 옳은가?
  • inverse 관계를 확인할 수 있는가?
  • 다른 수단을 사용해서 결과를 교차확인할 수 있는가?
  • 에러 조건을 강제로 만들어낼 수 있는가?
  • 성능이 한도 내에 있는가?

TDD의 한계

  • 추가적인 비용 발생. 단 이를 상쇄하고도 남을 만큼의 장기적인 이점을 가진다.
  • 동시성이 걸려 있는 코드에 대한 테스트 케이스 작성이 어려움.
  • private 메소드는 테스트가 불가능. 다만 private 메소드는 public 메소드 내에서 호출될 것이므로 public 메소드를 테스트할 때 private 메소드들도 함께 테스트가 된다고 볼 수 있다.
  • GUI 테스트의 어려움
  • 다른 클래스 및 메소드에 의존성이 있는 모듈에 대한 테스트가 어려움. Mock 객체를 사용하면 해결할 수 있다.

Reference: 테스트 주도 개발, 고품질 쾌속개발을 위한 TDD 실천법과 도구 - 채수원

쓰레드의 배타제어 (mutual exclusion) / 동기화 (synchronized) Mock