7

我在 StackOverflow 上的第一个问题。我希望能够做类似的事情:

SomeClass 模拟 = 模拟(SomeClass.class);

String methodName = "someMethod"; 或方法方法 = ...someMethod...

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

when(mock.someMethod()).thenReturn(null);

当然,“null”值将根据我的需要进行相应更改,但我试图确定两件事:

1)在Java中 甚至可以做这样的事情吗?= 将一个类对象和一个方法组合成一个方法调用。

2)我该怎么做这样的事情?

我已经无休止地研究了这个,我找不到任何东西。问题是,即使这适用于常规类和常规方法(someClass 和 someMethod 将一起执行 someClass.someMethod()),请记住,这必须与模拟对象一起使用,以便在 when( ) 称呼。

答案:when(method.invoke(mock)).thenReturn("Hello world."); 是正确的语法,反射确实在 when() 调用中起作用。谢谢凯文韦尔克!

4

2 回答 2

7

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

尝试使用反射,如:

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

虽然,我不确定这对你有什么用,因为你不能模拟/间谍类Method(它是最终的)。Mockitowhen()仅适用于模拟或间谍。如果这真的对你有用,你能发布更多细节吗?

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

对评论的补充回复 我知道这对你有什么作用,但我不确定你是否真的理解它是如何工作的。这可能很重要的原因是,未来对 Mockito 本身工作方式的更改可能会导致您的解决方案在未来被破坏。从本质上讲,它起作用的原因几乎是偶然的,但是是的,它会起作用。

应该起作用的方式when()是括号之间发生的是对先前创建的 Mockito 生成的模拟或间谍的方法调用,这只是一个类的精美代理,而不是该类的真实实例。代理具有特殊的逻辑来拦截假代理方法调用,并将其添加到已注册代理方法调用的列表中(它存储在称为 anIOngoingStubbing或类似的东西中)以供以后使用。由于 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为空,重要的是代理(即模拟)实例在调用when语句之前调用了正确的方法。

虽然 Mockito 不太可能改变事情在幕后工作的基本方式,但仍有可能在未来的某个时候为你打破。就像我说的,它起作用或多或少是一个快乐的意外。只要您了解它的工作方式和所涉及的风险,您就有更多的权力。

于 2012-04-12T21:09:21.400 回答
0

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

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

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

于 2012-04-12T13:29:43.480 回答