模拟基于反射的调用

时间:2012-01-25 22:10:03

标签: java mocking ejb-3.0 mockito

我试图模拟一些基于反射的方法。您可以在下面看到详细信息,

待测班级

public class TracerLog {
    @AroundInvoke
    public Object logCall(InvocationContext context) throws Exception {
        Logger logger = new Logger();
        String message = "INFO: Invoking method - " 
                + context.getMethod().getName() + "() of Class - " 
                + context.getMethod().getDeclaringClass();

        logger.write(message);
        return context.proceed();
    }
}

测试

public class TracerLogTest {

@Mock
InvocationContext mockContext;
@Mock
Logger mockLogger;
@InjectMocks
private TracerLog cut = new TracerLog();

@BeforeMethod
public void setup() {
    MockitoAnnotations.initMocks(this);
}

@Test
public void logCallTest() throws Exception {
    when(mockContext.proceed()).thenReturn(true);
    when(mockContext.getMethod().getDeclaringClass().getName()).thenReturn("someClass");
    cut.logCall(mockContext);
    verify(mockContext).proceed();
}

}

@Test
public void logCallTest() throws Exception {
    when(mockContext.proceed()).thenReturn(true);
    when(mockContext.getMethod().getName()).thenReturn("someMethod");
    when(mockContext.getMethod().getDeclaringClass().getName()).thenReturn("someClass");
    cut.logCall(mockContext);
    verify(mockLogger).write(anyString());
    verify(mockContext).proceed();
}

但是,测试因NullPointerException而失败。我知道我在反对嘲笑概念时做错了什么,但我不明白它是什么。你能否对它有所启发,并建议我如何测试这种方法?

感谢。

2 个答案:

答案 0 :(得分:21)

您需要一个Method对象和一个Class对象。根据你的评论,Mockito无法模拟一个方法,所以你需要一个真实的方法。我没有测试过这个,但我相信这会有用。而不是:

when(mockContext.getMethod().getName()).thenReturn("someMethod");
when(mockContext.getMethod().getDeclaringClass().getName()).thenReturn("someClass");

你需要:

// any method will do, but here is an example of how to get one.
Method testMethod = this.getClass().getMethod("logCallTest");

when(mockContext.getMethod()).thenReturn(testMethod);

显然,getName()将不再返回“someMethod”,getDeclaringClass().getName()将返回此测试类的名称(在示例中),但是虽然你无法选择他们返回的内容,但他们是什么返回仍然是确定性的,因此您应该能够验证您需要的任何内容。 (当然,如果您需要间谍或验证是否对Method对象本身进行了调用,那么您仍然会被卡住。)

答案 1 :(得分:3)

是的,问题是mockContext.getMethod()将返回null。所以每次运行它,然后在结果上调用一些东西(getDeclaringClass()或getName())你就会得到NPE。设置模拟时,您可能希望使用RETURNS_DEEP_STUBS默认答案。像

这样的东西
@Mock( answer = RETURNS_DEEP_STUBS ) private InvocationContext mockContext; 

应该这样做。