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

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

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

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

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


当前回答

确保不调用类中的方法的一种方法是使用dummy重写该方法。

    WebFormCreatorActivity activity = spy(new WebFormCreatorActivity(clientFactory) {//spy(new WebFormCreatorActivity(clientFactory));
            @Override
            public void select(TreeItem i) {
                log.debug("SELECT");
            };
        });

其他回答

让我引用官方文件:

重要的是,你在监视真实的物体! 有时候不可能使用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();

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

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可以修复该问题,但这并不是一个干净的解决方案。

你侦察真实物体的能力很重要

当使用间谍存根一个方法时,请使用doReturn()方法族。

when(Object)将导致调用可以抛出异常的实际方法。

List spy = spy(new LinkedList());

//Incorrect , spy.get() will throw IndexOutOfBoundsException   
 when(spy.get(0)).thenReturn("foo");

//You have to use doReturn() for stubbing    
doReturn("foo").when(spy).get(0);

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

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

另一个可能导致间谍问题的场景是,当您测试spring bean(使用spring测试框架)或在测试期间探查对象的其他框架时。

例子

@Autowired
private MonitoringDocumentsRepository repository

void test(){
    repository = Mockito.spy(repository)
    Mockito.doReturn(docs1, docs2)
            .when(repository).findMonitoringDocuments(Mockito.nullable(MonitoringDocumentSearchRequest.class));
}

在上面的代码中,Spring和Mockito都将尝试代理您的MonitoringDocumentsRepository对象,但Spring将首先代理,这将导致findMonitoringDocuments方法的真正调用。如果我们在存储库对象上放置间谍之后调试代码,它将在调试器中看起来像这样:

repository = MonitoringDocumentsRepository$$EnhancerBySpringCGLIB$$MockitoMock$

@SpyBean来拯救

如果改用@Autowired注释,我们使用@SpyBean注释,我们将解决上述问题,SpyBean注释也将注入存储库对象,但它将首先由Mockito代理,并在调试器中看起来像这样

repository = MonitoringDocumentsRepository$$MockitoMock$$EnhancerBySpringCGLIB$

下面是代码:

@SpyBean
private MonitoringDocumentsRepository repository

void test(){
    Mockito.doReturn(docs1, docs2)
            .when(repository).findMonitoringDocuments(Mockito.nullable(MonitoringDocumentSearchRequest.class));
}