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

时间:2012-07-23 20:35:03

标签: java junit mockito

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

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

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

MyClass是一个界面,myInstance是一个实现,如果重要的话。

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

9 个答案:

答案 0 :(得分:495)

让我引用the official documentation

  

关于监视真实物体的重要问题!

     

有时不可能在(对象)使用咒语间谍时使用。示例:

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

答案 1 :(得分:24)

我的案子与接受的答案不同。我试图为一个不在该包中的实例模拟一个包私有方法

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 解决了这个问题,因为它不是一个干净的解决方案。

答案 2 :(得分:14)

Tomasz Nurkiewicz的回答似乎并不能说明整个故事!

NB Mockito版本:1.10.19。

我非常喜欢Mockito newb,所以无法解释以下行为:如果有专家可以改善这个答案,请随意。

此处讨论的方法getContentStringValue final static

此行 调用原始方法getContentStringValue

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

此行调用原始方法getContentStringValue

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

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

让我们看看这里涉及的方法签名:它们都是static的{​​{1}}方法。 Javadoc都说要回归Matchers,这本身就有点难以理解。可能会检查作为参数传递的null对象,但结果要么从未计算过,要么丢弃。鉴于Class可以代表任何类,并且您希望不要调用模拟方法,nullisA( ... )的签名不能返回any( ... )而不是通用参数* null

反正:

<T>

API文档没有提供任何关于此的线索。它似乎也说这种“不要呼叫方法”行为的需要“非常罕见”。我个人总是使用这种技术 :通常我发现模拟涉及几行“设置场景”......然后调用一个方法然后在模拟中“播放”场景你上演的背景......当你设置风景和道具时,你想要的最后一件事是让演员进入舞台左边并开始表现出他们的心......

但这超出了我的工资等级...我邀请任何通过Mockito高级牧师的解释......

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

答案 3 :(得分:14)

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

答案 4 :(得分:3)

可能导致间谍问题的另一种情况是,您正在测试 spring bean (使用spring测试框架)或在测试过程中传播对象的其他框架。 strong>。

示例

@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代理,并且在调试器中看起来像这样< / p>

repository = MonitoringDocumentsRepository$$MockitoMock$$EnhancerBySpringCGLIB$

这是代码:

@SpyBean
private MonitoringDocumentsRepository repository

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

答案 5 :(得分:1)

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

有人有想法模拟final课程,并发现MockMaker

  

由于这与我们当前的机制不同,而且这个机制有不同的限制,因此我们希望收集经验和用户反馈,所以必须明确激活此功能才能使用;可以通过mockito扩展机制创建包含单行的文件src/test/resources/mockito-extensions/org.mockito.plugins.MockMakermock-maker-inline

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

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

我只需删除该行(或文件),spy()就可以了。

答案 6 :(得分:0)

确保不调用类中方法的一种方法是用虚拟对象覆盖该方法。

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

答案 7 :(得分:0)

为scala用户提供的答案:即使将doReturn放在首位也不起作用!参见this post

答案 8 :(得分:0)

晚点参加聚会,但是上述解决方案对我不起作用,因此分享我的0.02 $

Mokcito版本:1.10.19

MyClass.java

private int handleAction(List<String> argList, String action)

Test.java

MyClass spy = PowerMockito.spy(new MyClass());

关注对我不起作用(正在调用实际方法):

1。

doReturn(0).when(spy , "handleAction", ListUtils.EMPTY_LIST, new String());

2。

doReturn(0).when(spy , "handleAction", any(), anyString());

3。

doReturn(0).when(spy , "handleAction", null, null);

正在执行以下操作:

doReturn(0).when(spy , "handleAction", any(List.class), anyString());