Java Mockito 间谍方法不起作用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22374215/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 15:22:01  来源:igfitidea点击:

Mockito spy method not working

javamockingmockitospy

提问by Man?aux Pierre-Alexandre

I'm in trouble with mockito.spy method.

我在使用 mockito.spy 方法时遇到了麻烦。

I'm recently arrived on a "old" project and my first task is to add mockito in it, and to do real unit test :)

我最近来到一个“旧”项目,我的第一个任务是在其中添加 mockito,并进行真正的单元测试 :)

the project has many conception problems but its not the point here ;)

该项目有很多概念问题,但这不是重点;)

I explain my problem:

我解释我的问题:

I have a class

我有一堂课

public class Tutu{
  public Tutu(){
  }
}

public class Toto{
  public Toto(){
  }
  public int executeToto(Tutu tutu){
    //do some stuff
    return 5;
  }
}

public class Titi{
  private Toto toto;

  public Titi(){
     this.toto = new Toto();     
  }

  public void executeTiti(){
      //do some stuff
      Tutu tutu = new Tutu();
      int ret = this.toto.executeToto(tutu);
      //do some stuff
  }
}

in my test class TitiTest.java I want to test only executeTiti, I don't want to test executeToto stuff because this class has is own test class TotoTest.java.

在我的测试类 TitiTest.java 我只想测试 executeTiti,我不想测试 executeToto 的东西,因为这个类有自己的测试类 TotoTest.java。

but as you can see, toto is instantiate in titi constructor so I try something like this: (I'm using PowerMock in my test too, so I'm using PowerMockRunner but it doesn't seem to be the problem)

但正如你所看到的,toto 在 titi 构造函数中实例化,所以我尝试这样的事情:(我也在我的测试中使用 PowerMock,所以我使用的是 PowerMockRunner 但它似乎不是问题)

@RunWith(PowerMockRunner.class)
public class TitiTest {

 @Test
 public void testExecuteTiti(){
   Toto toto = Mockito.spy(new Toto());
   Mockito.doReturn(2).when(toto).executeToto(Mockito.any(Tutu.class));

   Titi testedObject = new Titi();
   testedObject.executeTiti();
 }
}

but the real method is always calling and ret = 5 everytime :(

但真正的方法总是调用并且每次 ret = 5 :(

Do I miss something? I read many post about this on stackoverflow and try all solution but it's never work because I think I'm doing right thing.

我错过了什么吗?我在stackoverflow上阅读了很多关于这个的帖子,并尝试了所有的解决方案,但它从来没有奏效,因为我认为我在做正确的事情。

I use junit4.11/powermock1.5.4/mockito1.9.5

我使用 junit4.11/powermock1.5.4/mockito1.9.5

采纳答案by Jeff Bowman

Toto toto = Mockito.spy(new Toto());

Bear in mind that this spies/stubs on the Toto instance you create in this line, and not every newly-created Toto. So when you call:

请记住,这会监视/存根您在此行中创建的 Toto 实例,而不是每个新创建的 Toto。所以当你打电话时:

Titi testedObject = new Titi();
testedObject.executeTiti();

The constructor new Titi()itself creates a new instance of Toto, unaffected by Mockito, so that call to this.toto.executeAction()will always return 5.

构造函数new Titi()本身创建了一个新的 Toto 实例,不受 Mockito 的影响,因此调用 tothis.toto.executeAction()将始终返回 5。



Because you're running with PowerMockito, you do have the option of stubbing Toto's constructor:

因为您使用 PowerMockito 运行,所以您可以选择存根 Toto 的构造函数

@RunWith(PowerMockRunner.class)
@PrepareForTest(Titi.class) // stub the calling class Titi, not Toto!
public class TitiTest {
  @Test public void testExecuteTiti() {
    Toto toto = Mockito.spy(new Toto());
    Mockito.doReturn(2).when(toto).executeToto(Mockito.any(Tutu.class));

    PowerMockito.whenNew(Toto.class).withAnyArguments().thenReturn(toto);

    Titi testedObject = new Titi();
    testedObject.executeTiti();
  }
}

But the option I like the best is to create a secondary constructor for Titi, for testing:

但我最喜欢的选项是为 Titi 创建一个辅助构造函数,用于测试:

public Titi(){
  this.toto = new Toto();     
}

/** For testing only. Uses the passed Toto instance instead of a new one. */
Titi(Toto toto){
  this.toto = toto;
}

Which then only requires you to adjust your test like this:

然后只需要您像这样调整测试:

@Test public void testExecuteTiti(){
  Toto toto = Mockito.spy(new Toto());
  Mockito.doReturn(2).when(toto).executeToto(Mockito.any(Tutu.class));

  Titi testedObject = new Titi(toto);
  testedObject.executeTiti();
}

回答by geoand

What you seem to be missing is the fact that your Spy for the Toto class is never actually being used by the Titi class.

您似乎缺少的是,您的 Toto 类的 Spy 从未真正被 Titi 类使用过。

What I would do in your case is

在你的情况下我会做的是

1) Refactor the Titi class to accept Toto as a dependency in the constructor. That way you can easily create Titi with any Toto (and there for use a mock in your unit test)

1)重构Titi类,在构造函数中接受Toto作为依赖。这样您就可以轻松地使用任何 Toto 创建 Titi(并在单元测试中使用模拟)

2) If option 1 is out of the question you could do the following:

2) 如果选项 1 不可能,您可以执行以下操作:

public class Titi{
  private Toto toto;

  public Titi(){
     this.toto = new Toto();     
  }

  public void executeTiti(){
      //do some stuff
      Tutu tutu = new Tutu();
      int ret = getToto().executeToto(tutu);
      //do some stuff
  }

  //package private - used for overriding via spying 
  Toto getToto() {
      return toto;
  }
}

@RunWith(MockitoJUnitRunner.class)
public class TitiTest {

 @Test
 public void testExecuteTiti(){
   Toto toto = Mockito.mock(Toto.class);
   when(toto.executeToto(Mockito.any(Tutu.class)).thenReturn(2);

   Titi testedObject = new Titi();
   testedObject = spy(testedObject);
   doReturn(toto).when(testedObject).getToto();

   testedObject.executeTiti();
 }
}

回答by chris topinka

Here's an article that describes using one-line methods or factory helper methods for testing classes that don't inject collaborators. https://code.google.com/p/mockito/wiki/MockingObjectCreation

这是一篇文章,描述了使用单行方法或工厂辅助方法来测试不注入协作者的类。https://code.google.com/p/mockito/wiki/MockingObjectCreation