그게 통합 테스트라고? 정말?

글을 시작하며 우선 참회한다. 나는 오래 전 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의 클라이언트 시스템 단위 테스트 케이스는 그 결과물이 동일하거나 거의 다르지 않다는 것 또한 유추할 수 있다.

시나리오 3의 클라이언트 시스템 단위 테스트와 같은 유형을 ‘Sociable Unit Tests’라고 부른다. Martin Fowler의 이 글을 참고하라.

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

내가 mockist가 아니라는 것이 테스트 대역을 절대 사용하지 않는다는 것을 의미하지는 않는다. 원격 서비스에 의존하는 개체를 단위 테스트 하기 위해 실제 서비스를 구동시키는 것은 어리석은 짓이다. 하지만 가급적 자제하고 필요하다고 생각되는 곳에만 사용한다. Kent Beck도 테스트 대역을 잘 사용하지 않는다고 말했는데 내가 classicist가 된 주요 계기 중 하나로 작용했다. 테스트 대역은 일종의 가정이고 가정이 늘어날 수록 실제 결과는 예측하기 어려워진다.

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

Write tests. Mostly unit.

참고 글

Advertisements

그게 통합 테스트라고? 정말?”에 대한 5개의 생각

  1. jino

    좋은 글 감사합니다. 그런데 서드파티를 이용할때, 위 1번의 Json.NET 의 경우에도 테스트 대역을 이용하지 않으신다고 하셨는데, 이건 테스트가 충분히 되었거나 기본 라이브러리 수준의 범용성을 가졌다는 전제로 말씀해주신건가요?

    응답
    1. Gyuwon 글의 글쓴이

      본문의 시나리오 1을 약간 보강했는데요, 테스트 케이스에서 쉽게 사용할 수 있고 오류가 발생할 가능성이 없거나 낮은 코드라고 보기 때문입니다. 플랫폼이 제공하는 기본 라이브러리도 테스트 케이스에서 사용하기 어렵다면 테스트 대역을 만드는 것이 현명할 수 있습니다. 예를 들면 UI 코드의 경우가 그렇죠.

      응답
  2. Momo

    잘 읽었습니다. 아직 테스팅을 부분적으로 시도해보고 배우고 있습니다.

    1번 시나리오는 사이드 이펙트가 없는 모듈이라면 저도 믿고 쓸 수 있을 거 같아요. 근데 2, 3번 시나리오는 테스트 대역이 없어서 발생할 수 있는 보이지 않는 사이드 이펙트가 더 불안 한데요. 그냥 연결해서 사용해도 되는
    걸까요?

    응답
    1. Gyuwon 글의 글쓴이

      부작용이 불안하다는 것은 그것으로 인해 단위 테스트 결과가 고립되지 않을 것 같은 불안함인가요? 그럼 만약 하나의 개체의 메서드를 테스트 할 때 그 메서드가 동일한 개체의 다른 메서드를 이용할 때도 불안함 때문에 테스트 대역을 준비하실 건가요? 오히려 테스트 대역 때문에 부작용으로 인한 오류가 숨겨지는 것이 더 해로운 것 아닐까요? 어쩌면 mockist들이 주장하는 ‘단위’의 경계가 합리적인지 돌아볼 필요가 있을 수도 있습니다.

      응답
  3. 견우

    공감합니다…. 결국엔 tdd를 하면서 kent beck 이야기했던 보폭에 대한 이야기인듯합니다.. 처음 tdd를 익힐땐 보폭으르잘게 쪼개야 마음이 편하지만 조금 익숙해지면 상황에 맞춰 보폭으르늘리기도 줄이기도하는것깉습니다.. 그래서 tdd를 개발을 하기 위한 도구라고 하나봅니다…
    글 잘 읽고갑니다

    응답

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중