개요

우리가 테스트 코드를 작성할 때 주로 쓰는 프레임워크는 xUnit으로 단위테스트 프레임워크를 말한다. 자바에서는 Junit이라는 프레임워크를 사용한다.
그럼 혹시 JUnit외에 다른 단위테스트 프레임워크는 없을까?

Spock

Spock는 BDD프레임워크로 기대하는 동작과 테스트 목적을 더 명확하게 작성할 수 있는 프레임워크다.

Groovy언어를 사용하여 테스트 코드를 작성하며 JUnit에 비해 더 간결하게 작성할 수 있고 JUnit에서 제공하는 주요 기능 모두를 지원하고있다.
Junit을 이용해 작성했을 때

@Test
void 테스트() {
  // Given
  String sample = null;

  // When & Then
  String result = sampleService.doSomething();
  assertThat(result).isEqualTo(sample);
}

Spock를 이용해 작성했을 때

def "샘플 테스트 케이스"() {
  given:
  def sample = null

  when:
  def result = sampleService.doSomething()

  then:
  result == null
}

특징으로는 메소드 이름을 문자열로 작성할 수 있다는 점과 원래는 주석으로 gwt패턴을 나타냈다면 Spock에서는 코드블록을 선언하여 나타낼 수 있다.

테스트 메소드는 def를 이용하여 함수로 선언하고 하나 이상의 블록이 존재해야한다.

  • given : 테스트에 필요한 값을 준비한다.
  • when : 테스트할 코드를 실행한다.
  • then : 예외 및 결과 값을 검증한다.
  • expect : than과 같고 where를 필요로하지 않아서 간단한 테스트 및 where과 같이 사용한다.
  • where : 데이터가 다르고 로직이 동일한 경우 동일한 테스트에 대한 중복 코드를 제거할 수 있다.

사용법

Spock를 사용하기 위해 플러그인과 의존성을 추가해야한다.

plugins {
  id 'groovy`
  id `java`
}
testImplementation 'org.spockframework:spock-core:2.4-M4-groovy-4.0'
testImplementation 'org.spockframework:spock-spring:2.4-M4-groovy-4.0'
implementation 'net.bytebuddy:byte-buddy:1.14.18'

이렇게 기본 의존성인 core와 스프링에서 사용하기 위해 spring의존성을 추가해주고 런타임에 클래스 기반 mock을 만들기 위해 buddy의존성을 추가해준다.

Testcontainers

단위테스트는 보통 service 계층을 대상으로 하고 실제 스프링 컨테이너를 띄워서 테스트할 경우 @SpringBootTest애노테이션을 붙여서 테스트한다.
이렇게 할 경우 실제 데이터베이스를 사용하여 테스트가 수행되는데 테스트 환경에서 데이터베이스를 사용하는 방법은 여러가지가 있다.

  1. 개발환경 DB사용하기
  2. 인메모리 DB사용하기(H2)
  3. 테스트 컨테이너 사용하기

1번의 경우 실제 DB환경과 비슷한 환경에서 하기 때문에 실제 환경에서도 비슷하게 동작할 것이라는 기대를 할 수 있지만 동시 다발적으로 테스트할 경우 어느 테스트코드에선 데이터를 삭제하고 다른 테스트코드에선 그 데이터를 조회한다면 테스트 코드를 실행할 때마다 다른 결과가 나올 수 있다.

2번의 경우 메모리에서 실행되기 때문에 빠른 테스트 속도를 기대할 수 있지만 실제 환경과 다른 스펙이기 때문에 운영환경에 대한 테스트를 수행해야하는 경우 실제 운영환경과 다른 결과를 얻을 수 있다는 단점이 있다.

테스트 컨테이너는 운영환경과 유사한 DB를 사용하고 독립적인 환경에서 테스트할 수 있는 방법이다.
테스트 코드가 실행될 때 도커 컨테이너를 이용해서 테스트히고 끝나면 컨테이너를 자동으로 정리해준다.

이제 테스트 컨테이너에 대해 자세히 알아보자

일단 의존성을 추가해주어야한다.