Mockito:试图窥探方法是在调用原始方法

本文翻译自: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()工作。

展开阅读全文
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值