티스토리 뷰

framework

Spock 개관

북항 2020. 5. 7. 18:46
donaricano-btn
반응형

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/ 의 내용을 참고했음을 밝힙니다.

반응형
donaricano-btn
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함