본문 바로가기
프로그래밍/테스트

[Spock] Spock Framework 이용하기 - 개론편

by 사바라다 2020. 8. 20.

[Spock] Spock Framework 이용하기 - 개론편
[Spock] Spock Framework 이용하기 - 실습편
[Spock] Spock Framework 이용하기 - Mock
[Spock] Spock Framework 이용하기 - Where

안녕하세요. 이전에 유닛테스트의 중요성 및 JUnit5에 대해서 포스팅을 했었습니다. 다들 도움이 되셨었나요? 오늘은 Spring에서 JUnit과 함께 많이 사용되는 Spock Framework에 대해서 알아보는 시간을 가지도록 해보겠습니다. 오늘은 Specification까지 알아보며 실제 사용은 다음 포스팅의 Block편에서 다루도록 하겠습니다.


Spock Framework

Spock은 java와 groovy application을 테스팅하기 위한 프레임워크입니다. JUnit이 java 언어기반의 테스트 언어라면 Spock Framework는 Groovy 언어 기반입니다. 즉, Java 언어로 만들어진 소스를 Groovy 언어를 통해서 테스팅하게 됨을 의미합니다. 그렇기 때문에 groovy 언어에 대한 이해서 필요합니다. 이런 이유로 배울때의 러닝커브는 JUnit보다 높다고 생각하며 실제로 그렇습니다. 하지만 조금만 익숙해지면 JUnit에서는 불편하던 많은 부분이 해결되게됩나다.

의존성

Spock Framework는 Groovy를 메인 언어로 사용하기 때문에 빌드도구(Maven, Gradle)에 groovy Plugin을 추가해 주어야합니다. 저는 gradle kotlin dsl을 사용하기 때문에 아래 와 같이 추가해 주었습니다.

pulgins {
    groovy
}

만약 일반적인 gradle을 사용하고 계시다면 아래와 같이 추가하면 됩니다.

apply plugin: 'groovy'

그리고 Spock Framework을 사용하기 위해서는 아래의 의존성을 추가해 주면 됩니다.

compile ('org.spockframework:spock-core:1.3-groovy-2.5')

package

spock의 경우 기본경로가 java package가 아닌 groovy package를 사용합니다. 아래와 같이 intellij에서 test를 생성하면 Testing library로 Spock을 선택할 수 있게 됩니다. 이렇게 Spock을 선택한 후 OK를 하게되면 test의 groovy package의 하위로 package가 설정되어 만들어지게 됩니다.

Create Test
Spock Framework Package Structure

Specification

이렇게해서 만들어지는 Spock Framework의 groovy 언어 클래스는 아래와 같습니다. 클래스 안에는 4가지 요소가 들어갈 수 있습니다. 맴버변수의 역할을 하는 Fields, JUnit의 LifeCycle 어노테이션과 동일한 역할을 하는 Fixture Methods, 실제 테스트하고자 하는 코드인 Feature Methods, 테스트에 재활용 할 수 있는 Helper Methods가 있습니다. 각각에 대해서는 아래에서 살펴보도록 하겠습니다.

import spock.lang.Specification

class BlogRepositoryTest extends Specification {
  // fields
  // fixture methods
  // feature methods
  // helper methods
}

Field

goovy는 동적 타입을 지원합니다. 즉, 데이터 타입에 맞게 맴버변수를 선언하지 않고 def를 이용해서 처리할 수 있습니다. 물론 정적 타입도 동일하게 사용할 수 있습니다. 아래와 같이 선언된 멤버변수들은 각 테스트 케이스(Feature Methods)마다 값을 공유하지 않습니다.

def obj = new ClassUnderSpecification()
Collaborator coll = new Collaborator()

다르게 테스트 케이스마다 동일한 객체를 공유해야하는 경우도 있습니다. 그럴 경웅에는 @Shared 어노테이션을 이용할 수 있습니다. 객체를 생성하는데 너무 비용이 크다던지 또는 테스트 케이스간의 연관관계를 가진다던지 할 때 사용할 수 있습니다.

@Shared res = new VeryExpensiveResource()

또 하나의 Field가 static final 멤버변수입니다. 이 Field는 상수(constants)를 표현하기위해 사용합니다. 이는 java와 동일합니다.

static final PI = 3.141592654

Fixture Methods

Fixture Methods는 JUnit의 라이프 사이클 메서드와 동일한 역할을 합니다. 즉, 각 테스트 케이스 전 또는 후로 실행되는 메서드를 정의합니다. JUnit에서 어노테이션을 이용했다면 Spock Framework에서는 정의된 메서드명을 이용해서 처리됩니다.

def setupSpec() {}    // 모든 테스트 케이스 실행 전 실행
def setup() {}        // 각 테스트 케이스 실행 전 마다 실행
def cleanup() {}      // 각 테스트 케이스 실행 후 마다 실행
def cleanupSpec() {}  // 모든 테스트 케이스 실행 후 실행

Fixture methods는 Test 환경을 세팅하고 정리하는 역할을 주로 합니다. Fields에 값을 넣거나 할 수 있습니다. 모든 fixture methods는 옵셔널하기 때문에 반드시 정의할 필요는 없습니다. 그리고 setupSpec과 cleanupSpec에서는 @Shared 인 Fields만 세팅 또는 정리할 수 있습니다.

feature methods

def "pushing an element on the stack"() {
  // blocks go here
}

feature methods는 실제 테스트 케이스를 작성하는 곳입니다. `def "{이름}" () {}`의 형식을 가지고 잇으며 이름에는 한글, 영문 특수문자 모두 가능합니다. Spock Framework 테스트의 전체적인 흐름은 아래와 같습니다. 여기서 feature emthods는 2번과 3번의 테스트 진행 및 결과 검증에 해당합니다.

  1. setup, setupSpec 실행 ( 옵션 )
  2. 테스트 진행
  3. 결과 검증
  4. cleanup, cleanupSpec 실행 ( 옵션 )

helper methods

각 테스트 케이스가 점점 많아질수록 중복 코드가 생기기 마련입니다. 이러한 경우 중복 코드를 하나의 메서드로 묵는데 이를 spock framework에서는 helper methods라고 합니다.

마무리

오늘은 이렇게 Spock Framework에 대해서 알아보았습니다. 개인적으로 JUnit을 사용하다 Spock을 사용하니 편하다는 생각이 많이 들었습니다. 이번시간에는 개론적인 부분이 대다수라 체감이 잘 안되실 수 있습니다. 다음시간에는 따라서 실습위주로 진행하고자 합니다. 다음 시간에는 feature methods의 block에 대해서 좀 더 자세히 알아보는 시간을 가지도록 하겠습니다.

감사합니다.

참조

http://spockframework.org

http://spockframework.org/spock/docs/1.3/index.html

댓글