本文翻译自:Mockito: Trying to spy on method is calling the original method
I'm using Mockito 1.9.0. 我正在使用Mockito 1.9.0。 I want mock the behaviour for a single method of a class in a JUnit test, so I have 我想在JUnit测试中模拟类的单个方法的行为,所以我有
final MyClass myClassSpy = Mockito.spy(myInstance);
Mockito.when(myClassSpy.method1()).thenReturn(myResults);
The problem is, in the second line, myClassSpy.method1()
is actually getting called, resulting in an exception. 问题是,在第二行中,实际上调用了myClassSpy.method1()
,从而导致异常。 The only reason I'm using mocks is so that later, whenever myClassSpy.method1()
is called, the real method won't be called and the myResults
object will be returned. 我使用模拟的唯一原因是,以便以后每次myClassSpy.method1()
,都不会调用real方法,并且将返回myResults
对象。
MyClass
is an interface and myInstance
is an implementation of that, if that matters. 如果很重要,则MyClass
是接口,而myInstance
是该接口的实现。
What do I need to do to correct this spying behaviour? 我需要怎么做才能纠正这种间谍行为?
#1楼
参考:https://stackoom.com/question/mkv1/Mockito-试图窥探方法是在调用原始方法
#2楼
Let me quote the official documentation : 让我引用官方文件 :
Important gotcha on spying real objects! 从事间谍活动的重要陷阱!
Sometimes it's impossible to use when(Object) for stubbing spies. 有时,不可能使用when(Object)来侦探间谍。 Example: 例:
List list = new LinkedList(); List spy = spy(list); // Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty) when(spy.get(0)).thenReturn("foo"); // You have to use doReturn() for stubbing doReturn("foo").when(spy).get(0);
In your case it goes something like: 就您而言,它类似于:
doReturn(resulstIWant).when(myClassSpy).method1();
#3楼
My case was different from the accepted answer. 我的情况与接受的答案不同。 I was trying to mock a package-private method for an instance that did not live in that package 我正在尝试为不存在于该程序包中的实例模拟程序包私有方法
package common;
public class Animal {
void packageProtected();
}
package instances;
class Dog extends Animal { }
and the test classes 和测试班
package common;
public abstract class AnimalTest<T extends Animal> {
@Before
setup(){
doNothing().when(getInstance()).packageProtected();
}
abstract T getInstance();
}
package instances;
class DogTest extends AnimalTest<Dog> {
Dog getInstance(){
return spy(new Dog());
}
@Test
public void myTest(){}
}
The compilation is correct, but when it tries to setup the test, it invokes the real method instead. 编译是正确的,但是在尝试设置测试时,它将调用real方法。
Declaring the method protected or public fixes the issue, tho it's not a clean solution. 声明一种受保护的方法或公开解决此问题,这不是一个干净的解决方案。
#4楼
The answer by Tomasz Nurkiewicz appears not to tell the whole story! Tomasz Nurkiewicz的回答似乎并没有说明整个故事!
NB Mockito version: 1.10.19. NB Mockito版本:1.10.19。
I am very much a Mockito newb, so can't explain the following behaviour: if there's an expert out there who can improve this answer, please feel free. 我是Mockito的新手,所以无法解释以下行为:如果有专家可以改善此答案,请放心。
The method in question here, getContentStringValue
, is NOT final
and NOT static
. 有问题的方法在这里, getContentStringValue
,是不是 final
和不是 static
。
This line does call the original method getContentStringValue
: 这行会调用原始方法getContentStringValue
:
doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), isA( ScoreDoc.class ));
This line does not call the original method getContentStringValue
: 该行不调用原始方法getContentStringValue
:
doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), any( ScoreDoc.class ));
For reasons which I can't answer, using isA()
causes the intended (?) "do not call method" behaviour of doReturn
to fail. 由于我无法回答的原因,使用isA()
会使doReturn
的预期(?)“请勿调用方法”行为失败。
Let's look at the method signatures involved here: they are both static
methods of Matchers
. 让我们看一下这里涉及的方法签名:它们都是Matchers
static
方法。 Both are said by the Javadoc to return null
, which is a little difficult to get your head around in itself. Javadoc都说这两个都返回null
,这本身很难理解。 Presumably the Class
object passed as the parameter is examined but the result either never calculated or discarded. 大概检查了作为参数传递的Class
对象,但是结果从不计算或丢弃。 Given that null
can stand for any class and that you are hoping for the mocked method not to be called, couldn't the signatures of isA( ... )
and any( ... )
just return null
rather than a generic parameter* <T>
? 鉴于null
可以代表任何类,并且您希望不调用模拟方法, isA( ... )
和any( ... )
的签名不能仅返回null
而不是通用参数* <T>
?
Anyway: 无论如何:
public static <T> T isA(java.lang.Class<T> clazz)
public static <T> T any(java.lang.Class<T> clazz)
The API documentation does not give any clue about this. API文档没有提供任何线索。 It also seems to say the need for such "do not call method" behaviour is "very rare". 似乎也说需要这种“不调用方法”的行为是“非常罕见的”。 Personally I use this technique all the time : typically I find that mocking involves a few lines which "set the scene" ... followed by calling a method which then "plays out" the scene in the mock context which you have staged... and while you are setting up the scenery and the props the last thing you want is for the actors to enter stage left and start acting their hearts out... 我个人使用这种技术的所有时间 :通常我发现嘲讽涉及的几行其中“设置场景” ......随后调用,然后将你所上演的模拟情境“中扮演了”现场的方法..当您设置风景和道具时,您想要的最后一件事就是让演员们进入舞台并开始演戏。
But this is way beyond my pay grade... I invite explanations from any passing Mockito high priests... 但这远远超出了我的薪水等级...我邀请任何过去的Mockito大祭司做解释...
* is "generic parameter" the right term? *“通用参数”是否正确?
#5楼
就我而言,使用Mockito 2.0,我必须将所有any()参数都更改为nullable()以便对实际调用进行存根。
#6楼
I've found yet another reason for spy to call the original method. 我发现间谍调用原始方法的另一个原因。
Someone had the idea to mock a final
class, and found about MockMaker
: 有人想到了模拟final
堂课的想法,然后发现了MockMaker
:
As this works differently to our current mechanism and this one has different limitations and as we want to gather experience and user feedback, this feature had to be explicitly activated to be available ; 由于此功能与我们当前的机制不同,并且此机制具有不同的局限性,并且我们希望收集经验和用户反馈,因此必须明确激活此功能才能使用; it can be done via the mockito extension mechanism by creating the file
src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
containing a single line:mock-maker-inline
通过创建文件src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
包含一行,可以通过mock-maker-inline
扩展机制来完成:
Source: https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods 来源: https : //github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classes方法
After I merged and brought that file to my machine, my tests failed. 合并并将该文件带到计算机后,测试失败。
I just had to remove the line (or the file), and spy()
worked. 我只需要删除行(或文件), spy()
工作。