【问题标题】:Mockito spy method not workingMockito 间谍方法不起作用
【发布时间】:2014-03-13 09:29:52
【问题描述】:

mockito.spy 方法有问题。

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

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

我解释我的问题:

我有课

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

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

但是正如你所看到的,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();
 }
}

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

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

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

【问题讨论】:

    标签: java mocking mockito spy


    【解决方案1】:
    Toto toto = Mockito.spy(new Toto());
    

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

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

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


    因为您使用的是 PowerMockito,所以您可以选择stubbing Toto's constructor

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

    但我最喜欢的选项是为 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;
    }
    

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

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

    【讨论】:

    • 您好,感谢您的帮助,在发布我的问题后,我终于更改了构造函数以传递好的实例及其工作。我只是想知道是否有其他解决方案,因为它是没有测试的遗留代码,我不想触及现有代码,但我同意你的看法,在这种情况下我别无选择:)谢谢
    • 我认为对遗留代码进行快速重构以使测试变得更好是值得的,但是您可以在不更改任何生产代码的情况下在答案中寻求 PowerMockito 解决方案。您可能需要调整 PowerMockito 代码;我的经验是有限的。祝你好运!
    【解决方案2】:

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

    在你的情况下我会做的是

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

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

    【讨论】:

    • 是的,就像我在上一个答案中所说的那样,我别无选择更改构造函数。也感谢您的帮助:)
    【解决方案3】:

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

    【讨论】:

    • 与其粘贴链接,不如在这里解释一下。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-01
    相关资源
    最近更新 更多