I'm in trouble with mockito.spy method.
I'm recently arrived on a "old" project and my first task is to add mockito in it, and to do real unit test :)
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.
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)
@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 :(
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.
I use junit4.11/powermock1.5.4/mockito1.9.5
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
来源:https://stackoverflow.com/questions/22374215/mockito-spy-method-not-working