사용자 도구

사이트 도구


java:spock

Spock

Dependencies

testCompile group: 'org.spockframework', name: 'spock-core', version: '1.1-groovy-2.4'
testCompile group: 'cglib', name: 'cglib-nodep', version: '3.2.4' // Class Mocking 할 때 필요.

Spock Feature Method 기본형태(test method)

// 일반적인 테스트
 
def "Feature Method name"() {
    :given "생략가능"
    // 테스트용 데이터 초기화
 
    :when
    // 테스트 대상 코드를 실행하고 실행 결과를 변수 등에 저장
 
    :then
    // 테스트 결과에 대한 검증.
    // 각 줄은 boolean 결과를 내는 Statement 로 작성한다.
    // 만약 한 줄의 코드가 boolean statement가 아니고 복잡한 구문일 경우에는 
    // 그 안의 assert boolean 구문에 'assert somebooleanexpression' 형태로 assert를 붙여야한다.
}
 
// Data Driven 테스트
def "Feature method name #a - #b = #c"(변수 a, 변수 b, 변수 c) {
    expect:
    // 각 데이터 변수로 테스트 수행
 
    where: "각 데이터 변수 설정"
    a | b || c
    1 | 2 || 3
    4 | 5 || 6
}

Mock Argument Capture

// Argument capture
def extern = null
 
1 * mock.foo( { extern = it; it.size() > 0 })  // 1.2 방식
1 * mock.foo( { it.size() > 0 }) >> { extern = it[0] } // 1.3 방식
  • void 메소드의 경우 아래 참조.

void method Mock - 인자 값 조정 혹은 throw exception

    // an interface with two methods: exists(user), add(user)
    def userService = Mock(UserService)
 
    // a controller to test, that will use mock of the service:
    def controller = new UserController(userService)
 
    def 'should throw exception for invalid username'() {
        given:
        def username = 'Joffrey Baratheon'
        userService.exists(_ as User) >> false
        userService.add(_ as User) >> { User user ->
            throw new IllegalArgumentException(user.name)
        }
 
        when:
        controller.addUser(username)
 
        then:
        def e = thrown(IllegalArgumentException)
        e.message == username
    }

Mock 선언이 작동하지 않을 때

  • 대상 Class 혹은 Method가 final로 선언돼 있으면 아무 오류없이 Mock 이 작동하지 않는다.

기타 Mock

0 * _   // 이 위 이후로는 어떠한 모의객체 호출 행위도 없어야 한다.

Spy

  • Spy() 사용시 스파이 대상 객체에 필드 인젝션이 안된다.
  • Spy객체 생성 후 Spring의 ReflectionTestUtils를 이용해서 따로 주입해주면 된다.

오류 / Error

  • Spock and Slf4j combination causes compilation error : Spock에서 @groovy.util.logging.Slf4j 사용시에 Error:Groovyc: The current scope already contains a variable of the name $spock_valueRecorder 오류가 발생하는 경우가 있다. Logger 직접 선언할 것.
  • 1.0 버전에서 메소드가 여러개 override 돼 있을 경우 Type 지정이 명확하지 않으면 잘못된 메소드를 호출할 수도 있다.
    // method 가 여러개로 override 돼 있을 경우 어떤 것이 호출될지 알 수 없음. 특히 return 도 서로 다를 때.
    expect:
    SomeClass.method(null) == null
     
    // 아래와 같이 파라미터와 리턴 타입을 모두 명시할 것.
    when:
    Result result = SomeClass.method(null as Request)
    then:
    result == null

Spock 1.3 & groovy 2.5 문제/변경점

where 의 변수명이 서로 다른 메소드에 동일하게 존재하는데 타입이 다를경우

Argument 의 각 줄을 assert 하게 변경되면서 capture 방식도 바뀜

  • 1.2 에서는 Argument 의 Closure 블록에서 조건을 체크하려면 전체를 하나의 true/false 를 반환하게 만들어야 했다.
  • 1.3 부터는 각 줄에 대해 then 처럼 각자 assert 를 수행하기 때문에 그럴 필요가 없어짐.
// 1.2 방식
1 * mock.foo({ it.size() > 1 &&  it[0].length == 2 })
 
// 1.3 - 한줄 한줄의 boolean 반환 결과를 자동 체크함.
1 * mock.foo({ 
    it.size() > 1
    it[0].length == 2 })
// Argument capture
def extern = null
 
1 * mock.foo( { extern = it; it.size() > 0 })  // 1.2 방식
1 * mock.foo( { it.size() > 0 }) >> { extern = it[0] } // 1.3 방식

참조

java/spock.txt · 마지막으로 수정됨: 2020/08/27 13:35 저자 kwon37xi