Groovy 기술을 이용해서 작성하지만 Groovy에서는 자바를 편하게 가져다 사용하기 때문에 자바 코드의 테스팅에도 사용할 수 있다. Groovy라는 새로운 언어에 대한 압박감이 있긴 하지만 자바를 안다면 Groovy는 100배 정도 쉽기 때문에 Groovy가 어려워서 Spock를 못쓰는 일은 없을 것이다.
class T02_SpockTest extends Specification {
// 기본적인 테스트 구성 불럭
def "Hello의 길이는 정말 5글자인가?"() {
// given: 테스트 하기 위한 기본 설정작업
given:
String str = "Hello";
// 테스트할 대상 코드를 실행
when:
int len = str.length();
// 테스트 결과 검증
then:
len == 6;
}
}
위는 Groovy를 이용한 Spock 사용의 예이다. 대략 보면 무슨 내용인지 알수 있을것 같다. (몰라도 크게 상관은 없긴 하다 ㅎㅎ 알아갈 예정이니까.)
환경 설정
intellij
이번 포스트에서는 intellij에서 gradle을 이용해 Spock을 사용할 계획이다. 이를 위해 두 가지를 설정해보자.
먼저 실행 옵션을 변경한다. 옵션의 Build, Execution> Build Tools > Gradle > Build and run으로 이동해서 Run tests using 부분을 Intellij IDEA로 변경한다. default인 Gradle을 사용하면 불필요한 로그도 많고 속도도 상대적으로 느리다.
다음으로 Spock 플러그인을 설치해보자. 이 플러그인은 테스트 클래스에서 Spock을 위한 구문 강조와 오류 표시를 지원한다.
프로젝트 생성과 build.gradle 설정
프로젝트를 구성할 때는 Gradle 기반으로 Java와 Groovy를 선택해주자.
적절한 프로젝트 이름(ex: spocktest)를 주로 프로젝트를 생성한다.
build.gradle을 열어보면 플러그인에는 groovy와 java가 설정되어있음을 확인할 수 있다.
plugins {
id 'groovy'
id 'java'
}
spock을 사용하기 위해서 반드시 있어야 할 의존성은 spock-core이다. 추가로 런타임에 클래스 기반 mock을 생성하기 위해서는 byte-buddy 가 필요하다.
testImplementation('org.spockframework:spock-core:1.3-groovy-2.5')
// 런타임에 클래스 기반 mock을 만들기 위해서 필요
testImplementation("net.bytebuddy:byte-buddy:1.9.3")
만약 스프링 부트로 앱을 개발 중이라면 아래의 의존성도 추가해주자.
// 스프링 연결
implementation("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
testImplementation("org.springframework.boot:spring-boot-starter-test:${springBootVersion}")
testImplementation('org.spockframework:spock-spring:1.3-groovy-2.5')
Hello Spock
junit vs spock
만약 기존에 junit을 사용해본 경험이 있다면 spock을 배우는 것 역시 매우 쉽다. junit의 주요 요소들은 모두 spock에 있기 때문이다. 둘의 구성요소를 비교해보면 아래와 같다.
junit
spock
의미
Test class
extends Specification
테스트 클래스 자체
@Test method
Feature
테스트 메서드
Assertion
Condition
검증 내용
Mocking
Interaction
거짓 객체와의 연동
@Before
setup()
각 테스트 시작 시 마다 한번 씩 수행(테스트 초기화)
@After
cleanup()
각 테스트 종료 시 마다 한번 씩 수행(테스트 정리)
@BeforeClass
setupSpec()
테스크 클래스 시작 시 한번 만 수행
@AfterClass
cleanupSpec()
테스트 클래스 종료 후 한번 만 수행
간단한 사용법
테스트 클래스는 Groovy 클래스로 생성하고 Specification 클래스를 상속 받는다.
feature(피터: 테스트 메서드)는 def를 이용해서 함수로 선언한다.
feature의 이름은 명명 규칙과 무관하게 작성하므로 한글로 의도를 명확지 써줄 수 있다.
정의될 블로별로 적절한 할일을 기입한다.
첫 번째 테스트 클래스 작성해보기
프로젝트의 src> test> groovy를 오른클릭해서 새로운 Groovy 클래스를 작성해보자.
package com.quietjun
import spock.lang.Specification
class T01_Lifecycle extends Specification{
def setupSpec(){
println "전체 Specification에서 딱 한번"
}
def setup(){
println "모든 테스트 마다 한번씩"
}
def "테스트 내용을 명명 규칙에 얽매이지 않고 명확히 작성할 수 있다."(){
expect:
println "첫 번쩨 테스트"
}
def "테스트 2"(){
expect: "when과 then이 합쳐진 구조이다."
println "두 번째 테스트"
}
def cleanup(){
println "모든 테스트 마다 한번씩 정리"
}
def cleanupSpec(){
println "전체 Specification에서 딱 한번 정리"
}
}
코드를 작성하면 라인번호 옆에 녹색의 왠지 실행할 것 같은 화살표 버튼들이 생성된다.
당연하게도 클래스 옆의 >>는 해당 클래스의 모든 테스트를 처리한다. 이때 테스트의 실행은 순서가 없음을 유의하자. 각각의 def 옆의 >는 해당 feature만 신행해준다.
위 테스트를 수행하면 setup, cleanup, setupSpec, cleanupSpec 그리고 feature 들의 실행 순서를 알 수 있다. 이때 첫 번째 테스트와 두 번째 테스트의 실행 순서는 보장되지 않음을 주의하자.
전체 Specification에서 딱 한번
모든 테스트 마다 한번씩
첫 번쩨 테스트
모든 테스트 마다 한번씩 정리
모든 테스트 마다 한번씩
두 번째 테스트
모든 테스트 마다 한번씩 정리
전체 Specification에서 딱 한번 정리
테스트 성공과 실패
T02_SpockTest
아직은 블록에 대한 설명을 하지 않았으므로 따라하기로 간단한 테스트를 만들고 성공과 실패가 어떻게 처리되는지 살펴보자.
다음은 Hello라는 문자열의 길이가 5글자임을 검증하는 테스트이다.
package com.quietjun
import spock.lang.Specification
class T02_SpockTest extends Specification {
// 기본적인 테스트 구성 불럭
def "Hello의 길이는 정말 5글자인가?"() {
// given: 테스트 하기 위한 기본 설정작업
given:
String str = "Hello"
// 테스트할 대상 코드를 실행
when:
int len = str.length()
// 테스트 결과 검증
then:
len == 5
}
}
테스트 성공 시
테스트가 성공했을 때는 언제나 반가운 녹색의 체크박스만 보면 된다. 테스트 프레임워크의 목적은 테스트 자동화이므로 통과했다는 정보만 의미있지 다른 정보는 대부분 의미가 없다.
테스트 실패 시
테스트가 실패하면 어떤 condition을 만족시키지 못했는지 알기 쉽게 표현해준다. 위 테스트 코드에서 len==6으로 수정 후 다시 한번 테스트를 진행해보자.
len ==6 부분에서 len이 5였기 때문에 5==6은 false라는 상세한 정보를 제공하고 있다.
하단의 <Click to see difference>를 클릭하면 별도의 화면에서 내용 확인이 가능하다.