Mockito:是否有可能将mock与方法名称结合起来在when()调用中创建一个methodCall?

时间:2012-04-12 13:22:20

标签: java class reflection methods mockito

我在StackOverflow上的第一个问题。我希望能够做到这样的事情:

SomeClass mock = mock(SomeClass.class);

String methodName =“someMethod”;或方法方法= ... someMethod ...

这两件事(模拟和方法)将结合起来执行以下操作:

:当(mock.someMethod())thenReturn(空);

当然,'null'值会根据我的需要进行相应更改,但我想确定两件事:

1)甚至可以在Java中执行类似 this 的操作吗? =将类对象和方法合并到methodCall中。

2)我该怎么做?

我无休止地研究了这个,我找不到任何东西。问题是,即使这适用于常规类和常规方法(someClass和someMethod会聚在一起做someClass.someMethod()),请记住这必须使用模拟对象在when()调用中使用。

ANSWERED:when(method.invoke(mock))。thenReturn(“Hello world。”);是正确的语法和反射确实在when()调用内工作。谢谢Kevin Welker!

2 个答案:

答案 0 :(得分:7)

由于您基本上要求我重新发布我的评论,并根据您的回复修改,作为答案,这里是:

尝试使用反射,如:

when(method.invoke(mock)).thenReturn("Hello world.");

虽然,我不确定这对你有用,因为你不能模拟/窥探班Method(这是最终的)。 Mockito的when()仅适用于模拟或间谍。如果这对您有用,您可以发布更多细节吗?

如果它不起作用,你可以 - 正如我在OP中的评论中所建议的那样 - 去CGLib路线并绕过Mockito。它首先看起来并不那么困难。在我的OSS项目Funcito不是一个模拟框架)中,我删除了许多Mockito CGLib代理代码并根据我的需要重写了它。它为代理类的世界和拦截方法调用提供了一个更简单的视图。

对评论的额外回应 我知道这对你有用,但我不确定你是否真的理解它是如何工作的。这可能很重要的原因是因为Mockito本身工作方式的未来变化可能会在未来破坏您的解决方案。从本质上讲,它起作用的原因几乎是偶然的,但是它会起作用。

when()应该起作用的方式是在括号之间发生的是对先前创建的Mockito生成的模拟或间谍的方法调用,这只是一个类的奇特代理,而不是一个真正的类实例。代理具有拦截伪代理方法调用的特殊逻辑,并且基本上将其添加到已注册的代理方法调用列表中(它存储在称为IOngoingStubbing或类似的东西中)供以后使用。由于Java在调用方法之前评估参数,因此可以保证在实际执行when()方法之前注册/记住代理方法调用。 when()所做的是从这个IOngoingStubbing中弹出,然后它成为调用thenReturns()的对象。

你没有“正确”使用它,但它仍然适合你。怎么样?嗯,所有需要发生的事情是需要调用代理上的方法,以便在IOngoingStubbing执行之前在when()中注册。您不是直接在代理上调用方法,而是通过将代理传递给Method.invoke()来间接调用代理上的方法。因此,条件得到满足,when()已经在IOngoingStubbing中注册了代理方法调用。

你可以在下面的代码中看到同样的“偶然”幸福,在你意识到Mockito是如何工作之前,它首先出现是没有意义的:

@Test
public void testSomething() throws Exception {
    List listMock = mock(List.class);
    Method m = List.class.getDeclaredMethod("get", int.class);
    m.invoke(listMock, Mockito.anyInt());

    when(null).thenReturn("Hello World");  // Huh? passing null?

    assertEquals("Hello World", listMock.get(0)); // works!
}

上述测试确实通过了!尽管when的参数为null,但重要的是代理(即模拟)实例在调用when语句之前调用了正确的方法。

虽然Mockito不太可能改变基本的工作方式,但未来某个时候仍有可能为你打破。就像我说的那样,它或多或少是一个幸运的事故。只要你理解它的工作方式和所涉及的风险,你就会有更大的力量。

答案 1 :(得分:0)

我认为,只要在提供给Mockito的接口或类中未指定方法,就不可能在类初始化之后添加新方法。您可以在初始化后更改类签名,这是不可能的。

对于存根方法调用,请查看:http://code.google.com/p/mockito/。存根方法调用有一个示例。

如果您想获得动态答案,而不是静态答案,则不应使用Mockito。使用虚假对象或存根来获取测试行为。有关此问题的详细信息,请参阅:http://martinfowler.com/articles/mocksArentStubs.html