TDD(Test-Driven Development, 테스트 주도 개발)에 익숙하지 않은, 개체지향 프로그래밍 언어를 사용하는, 프로그래머들은 간혹 이런 질문을 한다.

비공개(private) 메서드도 테스트 해야 하는가?

이 질문의 대답은 ‘그렇다’ 또는 ‘아니다’보다 좀 더 길다. 비공개 메서드의 인터페이스는 테스트 하지 않지만 비공개 메서드의 구현은 테스트 대상이다. 혼란스러울 수 있다. 어쩌라는 말인가?

 

이 혼란을 해결해 줄 대답은 TDD를 사용하는 프로그래머가 비공개 메서드를 만드는 목적과 과정에 있다. 우선 TDD에서 반복되는 3단계 과정을 요약하면 이렇다.

  1. 구현하고자 하는 아주 작은 기능 하나를 정의 또는 선택한 후 이 기능을 검증하는 테스트 케이스를 작성하고 작성된 테스트 케이스가 대상 기능이 구현되지 않은 이유로 실패하는지 확인한다.
  2. 전 단계에서 작성된 테스트 케이스를 비롯해 모든 테스트 케이스가 성공하도록, 그리고 성공할 만큼만 기능 코드를 작성한다.
  3. 모든 테스트 케이스가 성공하는 것을 확인하며 코드를 리팩터 한다.

이 과정을 흔히 Red-Green-Refactor라고 부른다.

개체지향 프로그래밍은 인터페이스를 노출하고 구현을 숨긴다. 테스트 케이스는 인터페이스에 의존적이며 구현에 독립적이다. 여기서 말하는 인터페이스는 개체의 공개(public) 멤버이다. 따라서 테스트 케이스는 개체의 공개 멤버를 통해서만 동작하며 내부 구현과는 직접 연결되지 않는다. Green 단계에서 프로그래머는 오로지 모든 테스트 케이스를 성공시키는 목적으로만 코드를 작성한다. 설계는 고려 대상이 아니다.

이후 Refactor 단계에서는 테스트 케이스 코드와 결과에 영향을 주지 않는 범위 내에서 구현을 다시 설계한다. 재설계 목적은 코드 품질을 높이는 것이다. 가독성을 높이고, 코드의 의도를 명확히 드러내고, 중복 코드를 제거하고, 코드 덩어리를 적당한 크기로 분배한다.(‘Factor’는 ‘인수분해 하다’라는 의미의 동사다.) 테스트 케이스가 있기 때문에 프로그래머는 안심하고 과감하게 코드를 리팩터할 수 있다. 비공개 메서드는 이 과정에서 만들어진다. 따라서 비공개 메서드에 담긴 코드는 이미 테스트 케이스를 통해 완전히 검증된 후 재배치된 것이다. 테스트 케이스가 비공개 메서드의 인터페이스에 대해 전혀 알지 못함에도 불구하고 말이다.

예를 들어, 최근에 작성한 FlushCommands 메서드는 6개의 비공개 메서드로 구성된다. 이 비공개 메서드들이 가진 모든 코드는 빠짐 없이 테스트 클래스에 의해 검증되는데, 테스트 케이스들은 FlushCommands라는 공용 인터페이스를 통해서만 소통한다. 테스트 케이스가 공용 인터페이스에만 의존하기 때문에 내부 구현은 숨겨지고 언제든 더 나은 구조로 변경될 수 있다. 이런 특성은 개체지향 원리와도 맞닿아 있다. 테스트 케이스는 클라이언트 코드다.

다시 질문의 답을 한 문장으로 정리하면 이렇다.

비공개 메서드의 모든 코드를 비공개 메서드에 독립적인 방법으로 테스트 하라.