2017-01-11 2 views
0

Mockito를 사용하여 Junit 테스트를 작성한 후 다음 호에 직면했습니다. 내 테스트 대신 실제 객체에 대한 메소드를 호출하고 객체를 모의하고 NullPointerException을 수신합니다. 여기 내 코드는 다음과 같습니다실제 객체를 호출하는 대신 Mock 객체를 호출하는 방법

public class JSFUtilsTest { 

    public JSFUtilsTest() { } 

    JSFUtils jsfUtils = mock(JSFUtils.class); 
    FacesContext facesContext = ContextMocker.mockFacesContext();  
    ExternalContext extContext = mock(ExternalContext.class);  
    Application app = mock(Application.class);  
    ExpressionFactory exFactory = mock(ExpressionFactory.class);  
    ELContext elContext = mock(ELContext.class);  
    ValueExpression valExp = mock(ValueExpression.class); 

    @Test 
    public void testResolveExpression() {   
     when(jsfUtils.resolveExpression("expression")).thenAnswer(new Answer<Object>(){ 
       public Object answer(InvocationOnMock invocation){                     
        when(facesContext.getApplication()).thenReturn(app); 
        when(app.getExpressionFactory()).thenReturn(exFactory); 
        when(facesContext.getELContext()).thenReturn(elContext); 
        when(exFactory.createValueExpression(elContext, "expression", Object.class)).thenReturn(valExp); 
        when(valExp.getValue(elContext)).thenReturn(anyObject()); 
        return valExp.getValue(elContext);                  
       } 
      }); 

     jsfUtils.resolveExpression(anyString()); 

     verify(jsfUtils).resolveExpression(anyString());   
     assertNotNull(jsfUtils.resolveExpression(anyString()));   
    } 

} 

대신 Mock에서 resolveExpression()을 호출하면 JSFUtils 객체가 호출됩니다. JSFUtils.java와 JSFUtilsTest.java는 다른 패키지에 있습니다. 아무도 나를 도울 수 있습니까? 미리 감사드립니다!

+0

. 일반적으로 여러분은'when'과'anyString()'을 사용하여 모의 객체를 설정할 수 있습니다. 그러나 실제 문자열로 메소드를 호출 할 것입니다. 당신은 거꾸로하고있는 것 같습니다. 또한 왜 당신의'Answer' 방법이 더 많은'when' setup을하는지 잘 모르겠습니다. 나는이 모든 일을 어떻게 할 것인지 이해하지 못합니다. – khelwood

+0

테스트하려는 메소드를 조롱하면 실제로 테스트하지는 않습니다. – khelwood

+0

귀하의 의견을 보내 주셔서 감사합니다. 이제 anyString()을 메서드 호출에서 when과 real string과 함께 사용합니다. 하지만 여전히 NullPointerException 내 문제가 – Slava

답변

0

이 예제는 실제 예제에서 모의 ​​메서드를 직접 호출하지 않고 OUT에 종속성을 주입한다고 가정합니다.

jsfUtils.resolveExpression("expression")에 전화 할 때 귀하의 모의 답변에 답변 할 것으로 예상됩니다. 사실 당신은 그것을 부르지 않습니다. 나는 그것을 jsfUtils.resolveExpression(anyString())으로 변경하고 특정 문자열로 호출해야 할 필요가 있다면 확인 블록을 확인하십시오 : verify(jsfUtils).resolveExpression("expression");

또한 jsfUtils.resolveExpression(anyString());으로 전화하는 것이 올바른 방법이 아닙니다. 방법 anyString()은 실제 호출이 아닌 스텁을 위해 설계되었습니다.

+0

고마워요! 제 예제에서 종속성을 주입하는 방법을 보여 주시겠습니까? – Slava

+0

예를 들어,'JsfUtils' 클래스의 생성자는'JsfUtils (FacesContext facesContext, ExternalContext extContext * 등등)'처럼 보일 수 있습니다. 물론 클래스에 7 가지 종속성이있는 것은 좋지 않으므로이를 분리하는 방법에 대해 생각할 수 있지만 이것이 또 다른 주제입니다.어쩌면이 의존성이 전혀 필요하지 않을 수도 있습니다. –

+0

'jsfUtils.resolveExpression' 결과를 계산할 때만 모든 모의 객체를 사용하고 있습니다. 그것은 모의하려고하는 것이 아닙니다. –

0

대신 Mock에서 resolveExpression()을 호출하면 JSFUtils 객체가 호출됩니다.

그런 다음 모의을 만들 수 있지만 스파이하지 않습니다의 분리를 강제로 테스트중인 클래스에 다른 방법의 반환 값을 조롱하려는 경우

//JSFUtils jsfUtils = mock(JSFUtils.class); 
JSFUtils jsfUtils = spy(new JSFUtils(/* mocks of dependencies if needed */)); 

그러나 이것은 단지 필요한 당신 단위.

내가보기에 귀하의 예에서는 그렇지 않습니다. 그러니 그냥 쓰기 :

//JSFUtils jsfUtils = mock(JSFUtils.class); 
JSFUtils jsfUtils = new JSFUtils(/* mocks of dependencies if needed */); 
@Test 
public void testResolveExpression() {   
    when(jsfUtils.resolveExpression("expression")).thenAnswer(new Answer<Object>(){ 
      public Object answer(InvocationOnMock invocation){                     
       when(facesContext.getApplication()).thenReturn(app); 
       when(app.getExpressionFactory()).thenReturn(exFactory); 
       when(facesContext.getELContext()).thenReturn(elContext); 
       when(exFactory.createValueExpression(elContext, "expression", Object.class)).thenReturn(valExp); 
       when(valExp.getValue(elContext)).thenReturn(anyObject()); 
       return valExp.getValue(elContext);                  
      } 
     });    
    jsfUtils.resolveExpression(anyString()); 
    verify(jsfUtils).resolveExpression(anyString());   
    assertNotNull(jsfUtils.resolveExpression(anyString())); 

이것은 어떤 의미하지 않습니다 당신은 테스트 대상 클래스의 방법을 모의 (컷) 다음 바로 그 같은 메서드를 호출합니다. 이렇게하면 컷의 동작은 아니지만 조롱 프레임 워크의 동작을 확인할 수 있습니다.

동일한 테스트 방법 내에서 메서드를 두 번 호출합니다. 당신은 그것을 피해야합니다.

이에 테스트를 변경해야합니다 :이되어 매우 혼란스러워 보이는

@Test 
public void testResolveExpression() { 
    // arrange (test case specific setup of mocks and DTOs) 
    when(facesContext.getApplication()).thenReturn(app); 
    when(app.getExpressionFactory()).thenReturn(exFactory); 
    when(facesContext.getELContext()).thenReturn(elContext); 
    when(exFactory.createValueExpression(elContext, "expression", Object.class)).thenReturn(valExp); 
    when(valExp.getValue(elContext)).thenReturn(anyObject()); 

    // act (call real method on real object) 
    Object result = jsfUtils.resolveExpression("a valid input"); 

    // assert 
    assertNotNull(result); 
} 
+0

답변 해 주셔서 감사합니다. 하지만 JSFUtils 객체를 사용할 수 없습니다. 왜냐하면 모의 FacesContext가 필요하기 때문입니다. JSFUtils 대신 mock을 사용하면 NullPointerException이 발생합니다. – Slava

+0

'getFacesContext()'는 정적 메서드이므로 * PowerMock (-ito) *을 사용하여 조롱해야합니다. 하지만 JSFUtil은 oracle에서 제공하는 클래스입니다. 왜 당신은 * 그것을 시험하고 싶습니까? –

+0

이것은 단위 테스트를위한 첫 번째 과제이며 나는 너무 어리 석다라고 생각합니다. – Slava

관련 문제