模拟基于reflection的调用

我试图模拟一些基于reflection的方法。 下面你可以看到细节,

被测试的class级

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而失败。 我明白我在反对嘲笑概念时做错了什么,但我不明白它是什么。 你能否对它有所启发,并建议我如何测试这种方法?

谢谢。

您需要一个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()将返回此测试类的名称(在示例中),但是虽然您无法选择它们返回的内容,但它们返回的内容仍然是确定性的,所以你应该能够validation你需要的任何东西。 (当然,如果您需要间谍或validation是否在Method对象上进行了调用,那么您仍然会被卡住。)

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

 @Mock( answer = RETURNS_DEEP_STUBS ) private InvocationContext mockContext; 

应该做的伎俩。