13장. 까다로운 테스트.

어떤 코드는 테스트하기 까다로운 코드들이 존재한다.
특히 스레드와 영속성에 연관된 코드를 테스트하는 것이 까다롭다.
이 장에서는 스레드와 영속성을 테스트하는접근 방법 두 가지 주제에 기반을 두어 어떻게 하는지 살펴본다.


멀티스레드 코드 테스트

기대한 대로 동작하는 코드를 작성하는 것은 어렵기에 단위 테스트를 작성하는 것이다.
동작하는 동시성 코드를 작성하는 것은 훨씬 더 어렵다.
동시성 처리가 필요한 애플리케이션 코드를 테스트하는 것은 기술적으로 단위테스트의 영역이 아닌 통합 테스트로 분류하는 것이 낫다.

스레드를 사용하느 코드에 대하 테스트는 느린 경향이 있다.
동시성 문제가 없다는 것을 보장하면서 실행 시간의 범위를 확장해야 하기 때문이다.
스레드에 관한 결함은 오랫동안 잠재해 있다가 없을 것 같다고 확신한 한참 후에 등장하기도 한다.

멀티스레드 코드를 테스트할 때는 다음 주요 주제를 따르자.

  • 스레드 통제와 어플리케이션 코드 사이의 중첩 최소화
    • 스레드 없이 다량의 어플리케이션 코드를 단위 테스트할 수 있도록 설계를 변경
    • 남은 작은 코드에 대해 집중적인 테스트를 작성

  • 다른 사람의 작업을 믿기
    • 자바 5 에는 동시성 유틸리티 클래스(java.util.concurrent 패키지)가 들어 있음
    • 예를 들어 생산자/소비자 문제를 직접 코딩하지 말고 다른 사람들이 유용성을 입증한 BlockingQueue 클래스 사용

데이터베이스 테스트

JUnit 테스트의 대다수는 속도가 빠르길 원한다.
영속적인 모든 상호 작용을 시스템의 한 곳으로 고립시킬 수 있다면 통합 테스트의 대상은 결국 상당한 소규모로 줄어들 것이다.
또한 데이터가 이미 데이터베이스에 있다고 가정하는 것은 어렵다.
시간이 지나면서 데이터는 변질될 것이고 테스트도 망가진다.
테스트 관점에서 데이터의 의미는 그것을 모두 데이터베이스에 부어 넣는 순간 사라진다. 테스트 안에서 데이터를 생성하고 관리하자.

머신에 있는 데이터베이스라면 가장 간단한 경로는 테스트마다 깨끗한 데이터베이스로 시작하는 것이다.
혹은 적절한 참조 데이터를 포함한 기존에 생성된 데이터베이스 인스턴스도 좋다.
매 테스트는 그다음 자기가 쓸 데이터를 추가하거나 그것으로 작업하면 테스트 간 의존성 문제를 최소화할 수 있다.
테스트 간 의존성 문제는 다른 테스트에서 남아 있던 데이터 때문에 어떤 테스트가 망가지는 것을 의미한다.

테스트를 위해 공유된 데이터베이스에만 접근할 수 있다면 좀 더 비침습적인 해법이 필요하다.
데이터베이스가 트랜잭션을 지원한다면 테스트마다 트랜잭션을 초기화하고 테스트가 끝나면 롤백시키자.
트랜잭션의 처리는 보통 @Before와 @After로 처리할 수 있다.

통합 테스트는 작성과 유지 보수가 어렵지만 여전히 테스트 전략의 필수적인 부분이다.
단위 테스트에서 검증하는 로직을 최대화하는 방향으로 통합 테스트의 개수와 복잡도를 최소화하자.

더 어려운 시나리오들에 대해서는 아래와 같은 전략을 사용하면 좋다.

  • 관심사를 분리시키기. 의존적인 코드는 고립시켜서 코드 베이스에 만연하지 않도록 하기
  • 느리거나 휘발적인 코드를 목으로 대체하여 단위 테스트의 의존성을 끊기
  • 필요한 경우에는 통합 테스트를 작성하되 단순하고 집중적으로 만들기