2012-07-23 103 views
201

我正在使用Mockito 1.9.0。我想嘲笑行为在JUnit测试类的一个方法,所以我有Mockito:试图窥探方法是调用原始方法

final MyClass myClassSpy = Mockito.spy(myInstance); 
Mockito.when(myClassSpy.method1()).thenReturn(myResults); 

问题是,在第二行,myClassSpy.method1()实际上是获取调用,从而导致异常。我使用mock的唯一原因是,以后只要调用myClassSpy.method1(),就不会调用真正的方法,并且会返回myResults对象。

MyClass是一个接口,而myInstance是一个实现,如果有关系。

我需要做些什么来纠正这种间谍行为?

回答

348

让我引用the official documentation

上刺探实物重要疑难杂症!

有时不可能使用when(Object)来存储间谍。例如:

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); 

你的情况,它会是这样的:

doReturn(resulstIWant).when(myClassSpy).method1(); 
+15

如果我用这个方法和我原来的一个还是日渐叫什么名字?可以有我通过的参数有问题吗?这里是整个测试: http://pastebin.com/ZieY790P 如果您的原始方法仍然被调用,则可能是因为您的原始方法是final的,所以'send'方法被称为 – 2014-08-21 15:02:49

+9

@EvgeniPetrov。 Mockito不会嘲笑最终方法,也不能警告你最终方法的嘲讽。 – MarcG 2014-12-08 21:01:31

+0

dothrow()也可以吗? – Gobliins 2015-01-23 13:17:09

19

我的情况是从接受的答案不同。我试图嘲弄为没有生活在那个包实例的包私有方法

package common; 

public class Animal { 
    void packageProtected(); 
} 

package instances; 

class Dog extends Animal { } 

和测试类

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(){} 
} 

汇编是正确的,但是当它试图建立的测试,它调用真正的方法。

声明保护公共修复的问题,寿它不是一个干净的解决方法。

+0

我遇到了类似的问题,但测试和包私有方法在同一个包中。我认为Mockito可能在包装私有方法方面存在问题。 – Dave 2017-05-11 02:19:42

7

Tomasz Nurkiewicz的回答似乎并没有说出整个故事!

NB Mockito版本:1.10.19。

我是一个Mockito newb,所以不能解释以下行为:如果有专家在那里谁可以改善这个答案,请随时。

问题的方法在这里,getContentStringValue,是finalstatic

此行确实调用原始的方法getContentStringValue

doReturn("dummy").when(im).getContentStringValue(anyInt(), isA(ScoreDoc.class)); 

此行调用原始的方法getContentStringValue

doReturn("dummy").when(im).getContentStringValue(anyInt(), any(ScoreDoc.class)); 

因我所不能回答的原因,使用isA()会导致doReturn的预期(?)“不呼叫方法”行为失败。我们来看看这里涉及的方法签名:它们都是static方法Matchers。 Javadoc说这两个都会返回null,这本身有点难以理解。假设检查参数时传递Class对象,但结果要么从未计算或丢弃。鉴于null可以代表任何类别,并且您希望不要调用模拟方法,所以isA(...)any(...)的签名不会返回null而不是通用参数* <T>

总之:

public static <T> T isA(java.lang.Class<T> clazz) 

public static <T> T any(java.lang.Class<T> clazz) 

API文档没有给出这方面有任何的线索。它似乎也表示,对这种“不称呼方法”行为的需求是“非常罕见的”。我个人一直使用这种技术:通常我发现嘲笑涉及到几个“设置场景”的行......然后调用一个方法,然后在你已经上演的模拟上下文中“播放”场景...而当你设置风景和道具时,你想要的最后一件事是让演员进入舞台左侧并开始表演他们的心...

但是这超出了我的薪酬等级..我邀请任何经过Mockito的高级牧师的解释......

*是“通用参数”的正确名词吗?

+0

我不知道这会增加清晰度或进一步混淆的问题,但在ISA()和任何()不同的是,ISA实际上并类型检查,而任何()系列方法的创建只是为了避免类型转换争论。 – 2016-11-17 00:05:49

+0

@KevinWelker谢谢。事实上,方法名称并不缺乏某种自我解释的质量。然而,无论如何,无论如何,我都会对天才Mockito设计师的问题提出质疑,因为他们没有足够的文档记录。毫无疑问,我需要阅读另一本关于Mockito的书。 PS实际上似乎没有什么资源可以教授“中级Mockito”! – 2016-11-20 21:49:29

+1

历史是,anyXX方法首先被创建作为处理类型转换的一种方式。然后当他们建议他们添加参数检查时,他们不想破坏现有API的用户,所以他们创建了isA()系列。知道any()方法应该一直进行类型检查,他们推迟改变这些方法,直到他们介绍了Mockito 2.X检修中的其他重大更改(我还没有尝试过)。在2.x +中,anyX()方法是isA()方法的别名。 – 2016-11-23 22:19:11

1

在我的情况下,使用Mockito 2.0,我必须将所有any()参数更改为nullable()以便存根真实调用。

+0

不要让这个321投票最高的答案让你失望,这解决了我的问题:)我一直在挣扎了几个小时! – 2017-11-21 15:55:18

0

我发现间谍打电话给原始方法的另一个原因。

有人有想法嘲笑一个final类,并发现了大约MockMaker

由于这种工作方式不同,以我们目前的机制,这其中有不同的限制,当我们要积累经验和用户反馈,这个功能必须明确激活才能使用;它可以通过扩展的Mockito机制,创建包含一个行的文件src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker来完成:mock-maker-inline

来源:https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods

后,我合并,并把该文件到我的机器,我的测试中失败了。

我只是删除行(或文件),并spy()工作。