Spock Introduction
WHAT IS SPOCK?
WHY SPOCK?
- 간결하고 가독성이 좋은 테스트를 작성 가능
- Mock 지원이 좋아서 사용이 편리
- 그루비를 사용해서, 자바 보다 다양한 표현력 가능
Simple Test in Spock
먼저 Spock은 어떤것인지 어떻게 사용하는지 가볍게 살펴보자
1 | def "리스트 첫번째 요소는 2를 리턴해야 한다"() { |
기존에 JUnit을 사용하고 있던 유저라면 크게 이질적이지 않게 받아들여질법한 코드이다.
조금 더 감동적인 부분은 다음에 있다..
테스트 실패시 출력되는 콘솔내용으로 오류를 파악하는데 용이하게 되어 있다.
Spock Basic
본격적으로 Spock 사용법을 알아보자
Dependency 추가
spock-core, 그리고 스프링을 사용한다면 spock-spring을 추가한다.
1 | <!-- Maven기준 pom.xml --> |
Spock Test 생성
spock.lang.Specification을 상속하기만 하면 된다1
2
3class SpockTest extends Specification {
}
Fixture Methods
테스트 전후처리에 사용되는 메소드들에 대한 정리
SPOCK | JUnit |
---|---|
def setup() | @Before |
def cleanup() | @After |
def setupSpec() | @BeforeClass |
def cleanupSpec() | @AfterClass |
Feature Methods
실제 테스트에 사용하는 메소드는 아래와 같이 정의한다1
2
3def "메소드명"() {
// Blocks
}
Blocks
- setup / given: 테스트에 필요한 객체나 환경 준비
- when: 테스트할 코드를 실행
- then: 예외/조건 확인, 모킹과 몇번 호출되었는지 확인 when과 꼭 함께 사용해야 한다
- expect: then과 같으며, when을 필요로 하지 않기 때문에 간단한 테스트에 사용
- where: parameterized 테스트용
@Shared
공유객체 사용을 위한 애노테이션1
2
3
4
5
6
7
8
9
10
11
12
13
14
15def sharedNumber = 0
def "SharedTest1"() {
when:
sharedNumber++
then:
1 == sharedNumber
}
def "SharedTest2"() {
when:
sharedNumber++
then:
2 == sharedNumber
}
Exceptions
익셉션 발생여부를 검증할 수 있다.
thrown()과 notThrown()을 사용한다.1
2
3
4
5
6
7def "ExceptionTest"() {
when:
throw new Exception("익셉션 발생 후 추가 작업 가능")
then:
Exception e = thrown()
e.getMessage() == "익셉션 발생 후 추가 작업 가능"
}
WHERE
테스트 로직은 동일하고, input값을 변경해 여러번 수행하고 싶을때 사용한다
1 | def "Parameterized Test"() { |
아래와 같이 테이블 형식으로도 사용할 수 있다1
2
3
4
5
6
7
8def "Data Table"() {
expect:
name.size() == length
where:
name | length
'Game' | 4
'Portal' | 6
}
@Unroll
Iteration 결과를 독립적으로 확인 하고 싶을때 사용한다1
2
3
4
5
6
7
8
9
10
def "#a와 #b 에서 더 큰 수는 #c 이다"() {
expect:
Math.max(a, b) == c
where:
a | b | c
1 | 2 | 2
3 | 4 | 4
6 | 5 | 5
}
Mock
아래와 같은 방식으로 Mock을 생성할 수 있다1
2def list = Mock(List)
List list = Mock()
기대값 설정하는 방법을 알아보자1
2
3
4
5
6
7
8
9def "기대값 설정 테스트"() {
given:
List<String> list = Mock()
when:
def actual = list.get(0)
then:
list.get(0) >> 'GamePortal' // 기대값을 설정한다
actual == 'GamePortal'
}
기타
- @Timeout : 타임아웃 설정 (단위 : 초)
- @Ignore : 선택 테스트 무시
- @IgnoreRest : 선택 외 무시
- @FailsWith (value=Exception, reason=“에러메세지”)
느낀점
- 올인원 느낌의 편리성이 있다(hamcrest, mockito등을 알필요가 없다)
- 짧은시간에 익힐 수 있다
- 테스트 코드가 간결해지고 쉬워졌다
- private field 나 메소드 접근이 가능하다
- 테스트 실패 결과가 좀 더 원인파악에 도움이 된다