Mockito spy method not working

纵然是瞬间 提交于 2019-12-04 17:36:32
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:

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.


Because you're running with PowerMockito, you do have the option of 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();
  }
}

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

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

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.

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)

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

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

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!