글을 시작하며 우선 참회한다. 나는 오래 전 mockist였다.

당시의 나를 비롯해 mockist들은 단위 테스팅에 많은 테스트 대역(test double)을 등장시키고 그래야만 단위 테스팅이며 그렇지 않으면 통합 테스팅이라고 주장한다. 하지만 미안, 난 이제 변절자야.

예전에 ‘단위 테스팅과 통합, 승인, 기능 테스팅’이란 글을 작성했다. 제목처럼 단위 테스팅, 통합 테스팅, 기능 테스팅이란 용어를 설명하는 글이다. 그런데 다른 용어에 비해 통합 테스팅은 상대적으로 내용이 간소하다. 길게 설명하고 싶지 않았기 때문인데 불친절하게도 그 이유에 대해서는 적지 않았다.

나는 대부분의 코드를 TDD로 작성하지만 요즘은 테스팅이나 TDD와 관련된 이슈에 별 관심이 없다. 테스팅과 TDD에 대해 더 알고 싶은 것이 없기 때문이다. 모든 것을 알고있는 것이 아니라 코드를 작성하거나 주변의 테스팅 관련 논의를 지켜보면서 이해하지 못해 불편한 것이 발견되지 않는 것이다. 예를 들어 더이상 mockist가 아니게 된 후로 나는 단위 테스트 코드와 통합 테스트 코드를 잘 구별하지 못하게 되었지만 상관없다. 게다가 둘을 구별하는 것은 이제 나에게 별로 중요하지 않다. 그러다보니 통합 테스팅에 대해 잘 얘기하지 않는다.

나는 테스트 케이스를 작성할 때 단위 테스팅을 할지 통합 테스팅을 할지 심각하게 판단하지 않는다. 다시 말하지만 그건 나에게 별 의미가 없는 고민이다. 중요한 것은 테스트 케이스가 없음으로 인해 불안함을 느끼는지다. 불안함의 원인은 주로 두가지다. 코드가 복잡해 요구사항을 충족시키는지 확신하지 못하거나 쉬운 코드이지만 행여나 잘 못 되었을 때 그 피해가 심각한 경우. 이 기준을 따르면 단위 테스팅과 통합 테스팅의 차이는 주요 관심사가 아니게 된다.

세 가지 시나리오를 살펴보자.


시나리오 1

여러 개의 상품 가격 합계를 계산헤 JSON 형식으로 출력하는 시스템(응집된 코드 집합)을 작성한다. JSON 직렬화 도구로 .NET 생태계에서 가장 보편적으로 쓰이는 Json.NET을 선택했다. 이 시스템의 단위 테스트 케이스를 작성하기 위해 Json.NET의 테스트 대역을 만들지는 않을 것이다. 더 극단적인 예로, + 연산자의 테스트 대역을 만드는 것은 어리석은 짓이다. 제정신인가?


시나리오 2

서비스 시스템과 이 시스템을 이용하는 클라이언트 시스템을 만든다. 서비스 시스템의 공개 API는 설계가 완료되었지만 서비스 시스템을 개발할 프로그래머가 휴무라 API를 기준으로 클라이언트 시스템이 먼저 개발된다. 아직 서비스 시스템은 만들어지지 않았기 때문에 클라이언트 시스템을 단위 테스트 하기 위해 서비스 시스템의 테스트 대역을 사용한다. 이후 서비스 시스템이 만들어지고 모든 요구사항에 대해 테스트 된다. 두 시스템이 모두 테스트 되었지만 두 시스템이 통합되었을 때에도 요구사항을 제대로 만족할지는 확신할 수 없다. 불안함을 느낀 프로그래머는 클라이언트 시스템이, 테스트 대역이 아닌, 실제 서비스 시스템 인스턴스를 사용하도록 설정해 통합 테스팅을 수행한다.


시나리오 3

시나리오 2와 동일한 프로그램을 개발하지만 이번 시나리오에서는 서비스 시스템이 먼저 개발된다. 서비스 시스템이 요구사항을 모두 만족하는 것을 단위 테스팅을 통해 검증한다. 이제 클라이언트 시스템을 만들 차례고 단위 테스팅도 함께 진행한다. 이번엔 클라이언트 시스템을 단위 테스트 하기 위해 서비스 시스템의 테스트 대역을 만들지는 않는다. 시나리오 1에서 Json.NET이나 + 연산자의 테스트 대역을 만들지 않는 것과 동일한 이유에서다. 충분히 테스트 된 서비스 시스템을 신뢰하기 때문이다.


시나리오 1을 통해 테스트 대역이 사용되지 않는다고 해서 그것이 항상 통합 테스팅이라고 볼 수 없다는 것을 보였고 시나리오 3을 통해 신뢰할 수 있는 시스템이 단위 테스팅에 이용되는 것은 문제될 것이 없다는 것을 설명했다. 또한 시나리오 2의 통합 테스트 케이스와 시나리오 3의 클라이언트 시스템 단위 테스트 케이스는 그 결과물이 동일하거나 거의 다르지 않다는 것 또한 유추할 수 있다.

물론 통합 테스팅으로 확실히 분류될 수 있는 경우도 있다. 하지만 테스트 대역을 사용하지 않으면 통합 테스팅이라는 주장은 받아들일 수 없다. 기능 테스팅과는 달리 이런 테스팅의 상당수는 테스트 케이스의 작성 및 실행 비용을 증가시키지도 않는다.

내가 mockist가 아니라는 것이 테스트 대역을 절대 사용하지 않는다는 것을 의미하지는 않는다. 하지만 나는 테스트 대역의 사용을 가급적 자제한다. Kent Beck도 테스트 대역을 잘 사용하지 않는다고 말했는데 내가 classicist가 된 주요 계기 중 하나로 작용했다. 테스트 대역은 일종의 가정이고 가정이 늘어날 수록 실제 결과는 예측하기 어려워진다.

나는 새 코드를 작성할 때 단위 테스트 케이스를 작성하고, 이미 작성된 둘 이상의 시스템이 조립되어 잘 동작하는지 확인할 때 통합 테스트 케이스를 작성한다. 목적이 둘의 구분 기준이다. 형식은 중요하지 않다.

참고 글