2014-03-05 1 views
3

자바 프로젝트에서 작업하고 Spock 프레임 워크를 사용하여 Groovy에서 단위 테스트를 작성하기 시작했습니다. 하지만 Spock의 조롱 기능에 문제가있어 누군가 내가 잘못하고있는 것을 알아낼 수 있기를 바랍니다.Spock이 구체적인 수업을 올바르게 조롱하지 않았습니까?

나는 세 개의 자바 클래스를하십시오 FooContext (즉, foo 속성을 포함)하는 HasFooContext 클래스 (즉, fooContext 속성이 포함), 및 HasFooContext에서 상속 (그리고 fooContext를 호출하는 동작이있다)을 FooService :

public class FooContext { 
    private Object foo = new Object(); 
    public Object getFoo() { 
    return foo; 
    } 
} 

public abstract class HasFooContext { 
    private FooContext fooContext; 
    public void setFooContext(FooContext fooContext) { 
    this.fooContext = fooContext; 
    } 
    public Object getFoo() { 
    Object foo = fooContext.getFoo(); 
    assert foo != null : "no foo available"; 
    return foo; 
    } 
} 

public class FooService extends HasFooContext { 
    public void doFoo() { 
    getFoo(); 
    } 
} 
FooServicedoFoo 방법은 차례로 그 fooContext 속성의 getFoo 메소드를 호출 기본 클래스 HasFooContext에있는 getFoo 메서드를 호출하는 것을 여기에서 볼 수있다

. 또한 fooContext.getFoo()에서 반환 된 값이 null이 아니라고 주장합니다. 예상대로

public class FooServiceJavaUnitTest { 

    private FooContext fooContext; 
    private FooService fooService; 

    @Before 
    public void setup() { 
    Object foo = new Object(); 

    fooContext = mock(FooContext.class); 
    when(fooContext.getFoo()).thenReturn(foo); 

    fooService = new FooService(); 
    fooService.setFooContext(fooContext); 
    } 

    @Test 
    public void doFooInvokesGetFoo() { 
    fooService.doFoo(); 
    verify(fooContext, times(1)).getFoo(); 
    } 

} 

이 테스트가 성공적으로 실행 :

나는 doFoo를 호출하면 fooContext.getFoo() 메소드를 호출하는지 확인하기 위해, Mockito를 사용하여 자바에 다음과 같은 단위 테스트를 썼다.

은 그때 사용, 그루비에서 다음 단위 테스트를 작성 스팍 :

class FooServiceGroovyUnitTest extends Specification { 

    private FooContext fooContext; 
    private FooService fooService; 

    def setup() { 
    // Create a mock FooContext. 
    fooContext = Mock(FooContext) 
    fooContext.getFoo() >> new Object() 

    fooService = new FooService() 
    fooService.fooContext = fooContext 
    } 

    def "doFoo invokes getFoo"() { 
    when: "call doFoo" 
    fooService.doFoo() 

    then: "getFoo is invoked" 
    1 * fooContext.getFoo() 
    } 

} 

다음과 같이 테스트가 실패 :

FooServiceGroovyUnitTest.doFoo이 getFoo 호출 : 21 사용할 수 없음 foo는

즉, Groovy/Spock을 사용할 때는 실패하지만 Java/Mockito를 사용할 때는 실패합니다.

public abstract class HasFooContext { 
    ... 
    public Object getFoo() { 
    Object foo = fooContext.getFoo(); 
    assert foo != null : "no foo available"; 
    return foo; 
    } 
} 

FooContextfoo 속성은 final이 아니므로 getFoo() 메서드는 final이 아니어야하므로 생성 된 프록시는 해당 메서드를 가로 챌 때 아무런 문제가 없어야합니다 (Java/Mockito 테스트 별).

class FooServiceGroovyUnitTest extends Specification { 
    ... 
    def setup() { 
    // Spy on a real FooContext. 
    fooContext = Spy(FooContext) 

    fooService = new FooService() 
    fooService.fooContext = fooContext 
    } 
} 

을 다음 그루비/스팍 단위 테스트를 통과 다음과 같이 내가 구체적인 FooContext에 스파이로 모의 FooContext를 교체하면 것을

참고. 이는 구체적 클래스를 조롱하거나 구체적인 클래스를 염탐 할 때 동작이 다르다는 것을 의미합니다. Spock 문서에 따르면 모의 API는 동적 프록시를 사용하는 인터페이스와 CGLIB를 사용하는 클래스를 모두 지원합니다.

Java/Mockito 유닛 테스트와 Groovy/Spock 유닛 테스트는 동등하지만, FooContext 클래스를 조롱 할 때 Groovy/Spock 유닛 테스트를 통과 할 수 없습니다.

내가 뭘 잘못하고 있는지에 대한 제안이 있으십니까?같은 상호 작용의

답변

1

비웃음과 스터 빙은 같은 성명에서 일어날 필요가있다 : (Mockito의 주목할만한 예외)

1 * fooContext.getFoo() >> new Object() 

대부분의 다른 Java 조롱 프레임 워크 같은 방식으로 작동합니다. 이 동작에 대한 자세한 내용은 official documentation을 참조하십시오.

+0

의견을 보내 주셔서 감사합니다. 제안 된 변경이 이루어지면 Groovy/Spock 테스트가 통과됩니다. 설치 프로그램의'getFoo() >> new Object()'표현식이 mockito'when (...). thenReturn (...)'표현식과 동등하게 동작한다고 생각했습니다. 그래서'1 * fooContext.getFoo()'가'1 * fooContext.getFoo() >> null'과 같은 경우입니까? –

+0

편집 : 문서 (http://docs.spockframework.org/en/latest/interaction_based_testing.html#combining-mocking-and-stubbing 참조)에 따라 'null'이 실제로 반환됩니다. –

관련 문제