我使用的是Mockito 1.9.0。我想在JUnit测试中模拟类的单个方法的行为,所以我有

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

问题是,在第二行中,myClassSpy.method1()实际上被调用了,导致了一个异常。我使用模拟的唯一原因是,以后无论何时调用myClassSpy.method1(),都不会调用真正的方法,并且将返回myResults对象。

MyClass是一个接口,myInstance是它的实现。

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


当前回答

正如在一些评论中提到的,我的方法是“静态的”(尽管是由类的实例调用的)

public class A {
  static void myMethod() {...}
}
A instance = spy(new A());
verify(instance).myMethod(); // still calls the original method because it's static

解决方法是创建一个实例方法,或者通过一些配置将Mockito升级到一个新版本:https://stackoverflow.com/a/62860455/32453

其他回答

在我的例子中,使用Mockito 2.0,我必须将所有any()参数更改为nullable(),以便存根真正的调用。

我找到了间谍调用原始方法的另一个原因。

有人想要模拟最后一个类,然后发现了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()就可以工作了。

我的情况与公认的答案不同。我试图模拟一个包私有方法的实例,该实例不在该包中

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

编译是正确的,但是当它试图设置测试时,它反而调用了真正的方法。

将方法声明为protected或public可以修复该问题,但这并不是一个干净的解决方案。

让我引用官方文件:

重要的是,你在监视真实的物体! 有时候不可能使用when(Object)来攻击间谍。例子: List List = new LinkedList(); List spy =间谍(列表); //不可能:real方法被调用,所以spy.get(0)抛出IndexOutOfBoundsException(列表仍然为空) 当(spy.get (0)) .thenReturn (" foo "); //你必须使用doReturn()进行存根 doReturn(“foo”)当(间谍). get (0);

在你的情况下,它是这样的:

doReturn(resultsIWant).when(myClassSpy).method1();

Tomasz Nurkiewicz的回答似乎并没有说出全部的故事!

NB模仿版本:1.10.19。

我是一个非常多的Mockito新手,所以不能解释以下行为:如果有一个专家在那里谁可以改善这个答案,请随意。

这里讨论的方法getContentStringValue不是最终的,也不是静态的。

这一行调用了原始方法getContentStringValue:

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

这一行不调用原始方法getContentStringValue:

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

由于我无法回答的原因,使用isA()会导致预期的(?)doReturn的“不调用方法”行为失败。

Let's look at the method signatures involved here: they are both static methods of Matchers. Both are said by the Javadoc to return null, which is a little difficult to get your head around in itself. Presumably the Class object passed as the parameter is examined but the result either never calculated or discarded. 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>?

无论如何:

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. 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...

但这远远超出了我的职权范围…我请路过的Mockito大祭司解释一下…

*“通用参数”是正确的术语吗?