在真实对象上调用方法而不是调用Mock对象

时间:2017-01-11 09:19:43

标签: java unit-testing jsf junit mockito

当我使用Mockito编写Junit测试时,我遇到了下一个问题。我的测试调用真实对象上的方法而不是模拟对象,我收到NullPointerException。这是我的代码:

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位于不同的包中。有谁能够帮我?提前谢谢!

2 个答案:

答案 0 :(得分:0)

我认为这只是一个示例,在实际测试中,您不直接在模拟上调用方法,而是将依赖项注入OUT。

当你打电话给jsfUtils.resolveExpression("expression")时,你期待你的模拟回答。事实上,你没有打电话给它。我建议将其更改为jsfUtils.resolveExpression(anyString()),如果您需要使用某个特定字符串调用它,可以将其检查为验证块:verify(jsfUtils).resolveExpression("expression");

同样调用jsfUtils.resolveExpression(anyString());不是正确的做法。方法anyString()设计用于存根而不是真正的通话。

答案 1 :(得分: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 );  
}