-
반응형
Spock은 Groovy문법을 사용한 단위 테스트 프레임워크입니다. Spock은 다른 테스트 프레임워크에 비해 시간을 아낄 수 있고 Stubbing, Mocking, Spying 작업들을 아주 간단한 코드로 할 수 있습니다. 또한 Spock는 요즘 핫한 BDD에 적합한 프레임워크라고 합니다. 오늘은 이처럼 다양한 장점을 가진 Spock을 간단하게 살펴보도록 하겠습니다.
def "나이가 30살이다"() { given: def age when: age = 29 then: 30 == age }
위 코드는 잘 못된 코드이기 때문이기 때문에 테스트가 실패합니다. 이 때 Spock는 명확하고 아름답게 오류 메세지를 표시해 줍니다. 이것은 Spock을 사용하는 또 다른 이유입니다.
Condition not satisfied: 2 == age | | | 29 false
다시 위의 코드로 돌아가서 코드의 각 부분을 살펴봅시다. 일단 메서드의 이름을 따옴표 안에 표현 가능하다는 것을 알 수 있습니다. 이를 통해 보다 쉽고 간편하게 테스트 코드의 목적을 표현할 수 있습니다.
메서드 안의 코드는 세 부분으로 나뉘어지는 것을 알 수 있는데. 실제 테스트 하고자 하는 기능을 지정하는 given, 실제로 테스트를 진행하는 when, 마지막으로 결과를 확인하는 then입니다. BDD에 대해 알고 있는 독자라면 이 구분된 섹션들의 배열이 BDD와 매우 어울린다는 것을 알 수 있을 것입니다.
이제 Spock가 가진 기능들로 눈을 돌려 보겠습니다. 먼저 Stub을 살펴볼까요? Stub을 생성하기 위해서는 Spock코드 내에서 Stub() 메서드를 호출하면 됩니다.
def "리스트의 사이즈는 3이다"() { given: List list = Stub() list.size() >> 3 expect: // let's see if this works list.size() == 3 }
기본적으로 Stub을 사용하여 수행하는 작업은 Stub화 된 클래스의 메서드가 호출 될 때 발생하는 작업을 정의 하는 것입니다. 위 코드에서 >> 연산자를 사용해서 Stub화 된 메소드의 리턴값을 3으로 지정하고 있습니다. 만약 예외 등과 같은 사이드 이펙트를 원한다면 다음과 같이 하면 됩니다.
def "리스트의 사이즈를 호출하면 예외를 던진다"() { given: List list = Stub() list.size() >> { throw new IllegalStateException() } }
이제는 또다른 기능인 Mock을 살펴보겠습니다. Mock역시 Mock() 메서드를 통해 호출 할 수 있습니다.
def "사이즈 메소드는 한 번만 실생된다"() { given: List list when: list = Mock() then: 1 * list.size() }
Mock은 인터페이스의 관계를 확인하기 보다는 상호작용을 확인하기 위해 자주 사용합니다. 위 코드에서 then 섹션에서 상호작용 여부를 확인할 수 있습니다. size 메소드가 한 번 호출되었다고 했지만 사실은 한 번도 호출된 적이 없기 때문에 이 테스트는 실패하게 됩니다.
상호작용의 발생 횟수 뿐 아니라 순서 역시 확인할 수 있습니다.
def "커밋 전에 저장 되어야 한다"() { given: UserService service = Mock() Transaction transaction = Mock() when: service.save(new User()) transaction.commit() then: 1 * service.save(_ as User) then: 1 * transaction.commit() }
이제 Spy에 대해 알아보겠습니다. Spy가 Stub이나 Mock과 다른것은 Spy는 더미개체가 아니고 일반 개체에 대한 래퍼라는 것입니다. Spy를 생성할 때 이 점을 유의해야 합니다.
def "save 메소드를 호출한다"() { given: Transaction transaction = Stub(Transaction) UserService service = Spy(UserServiceImpl, constructorArgs: [transaction]) when: service.save(new User(name: 'Katherine')) then: 1 * service(_) }
Mock과 Spy가 다른 점은 Spy가 실제 호출되는 메소드의 동작을 변경하지 않았다는 것입니다. 특정 멧드가 호출되었는지 확인하고싶을 때 주로 Spy를 사용하게 됩니다.
지금까지 아주 간단하게 Spock을 알아봤습니다. 이 포스트의 내용은 상당부분 https://thejavatar.com/testing-with-spock/ 의 내용을 참고했음을 밝힙니다.
반응형