Метод шпиона мокито не работает
У меня неприятности с мокито.шпионский метод.
Я недавно прибыл на "старый" проект, и моя первая задача-добавить в него 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 вещи, потому что этот класс имеет свой собственный тестовый класс Тототест.Ява.
Но, как вы можете видеть, 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
3 ответа:
Toto toto = Mockito.spy(new Toto());
Имейте в виду, что это шпионы/заглушки на экземпляре Toto, который вы создаете в этой строке, а не каждый вновь созданный Toto. Поэтому, когда вы звоните:
Titi testedObject = new Titi(); testedObject.executeTiti();
Конструктор
new Titi()
сам создает новый экземпляр Toto, не затронутый Mockito, так что вызовthis.toto.executeAction()
всегда будет возвращать 5.
Поскольку вы работаете с 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(); } }
Но вариант, который мне больше всего нравится, - это создать вторичный конструктор для Тити, для тестирования:
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(); }
То, что вы, кажется, упускаете, - это тот факт, что ваш шпион для класса Toto никогда на самом деле не используется классом Titi.
Что бы я сделал в вашем случае, это
1) рефакторинг класса Titi для принятия Toto в качестве зависимости в конструкторе. Таким образом, Вы можете легко создать Titi с любым Toto (и там использовать макет в вашем модульном тесте)
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(); } }
Вот статья, в которой описывается использование однострочных методов или вспомогательных методов фабрики для тестирования классов, которые не вводят коллаборационистов. https://code.google.com/p/mockito/wiki/MockingObjectCreation