Юнит-тестирование с mockito (частичное издевательство)
У меня проблема с Мокито.
Можно ли сделать такую вещь:
ClassX x = mock(ClassX.class)
when(x.methodB()).thenReturn("toto");
String result = x.methodA();
Я работаю с Mockito 1.7.
Я видел, что была "шпионская" система, но они говорят, что не рекомендуется использовать ее (почему?) На предмете, который мы тестируем...
Я все равно попробовал эту шпионскую функцию, но у меня странное поведение.
Проверьте, что я хочу сделать:
Реальный код:
String methodA(String arg) {
return this.methodB(arg);
}
String methodB(String arg) {
return "toto";
}
Тестовый код:
@Test
public void testTest() {
final ClassX x = spy( new ClassX() );
final String argument = "arg";
doReturn("good").when(helper).methodB(argument);
assertTrue( x.methodB(argument).equals("good") );
assertTrue( x.methodA(argument).equals("good") );
}
Как они сказали, я избегал синтаксиса when thenReturn, который мог быть проблемой со шпионом (но он все равно не работает)
Странно то, что: assertTrue( x.methodB(аргумент).equals("хорошо")); в порядке
Только второй assertTrue( x.methodA(аргумент).equals("хорошо")); не в порядке
На самом деле helper.methodA(аргумент) возвращает "toto" -> реальный результат, а не фиктивный результат
В этом случае невозможно сказать, чтобы mockito вернул "хорошо"??? Кажется, когда тестовый класс вызывает methodB, это нормально, но если метод шпиона вызывает метод B, он больше не работает...
Я не знаю, что делать... это так странно, что юнит-тестирование 2 методов одного и того же класса делает тесты независимыми друг от друга, так что известный фреймворк mock-test не реализует эту основную функцию? Разве это не то, что мы называем настоящим юнит-тестированием? Не понимаю, почему они говорят, чтобы избежать использования шпионского метода на тестируемом объекте...
Спасибо
2 ответа
Шпион - это объект, отличный от шпионского объекта. Шпион только делегирует шпионскому объекту. Поэтому, когда шпионский объект вызывает methodB из methodA, он вызывает его сам, а не шпион.
ОБНОВЛЕНИЕ: я написал материал ниже, а через несколько мгновений обнаружил.thenCallRealMethod(), который позволяет эффективно выполнять частичную заглушку. Авторы Mockito рекомендуют использовать рефакторинг для разделения зависимостей на разные классы; но они дают возможность частично заглушить. Я добавил тестовый метод, чтобы продемонстрировать этот подход, и оставляю свои оригинальные комментарии.
ОРИГИНАЛ: Мне действительно нравится Mockito, но это единственное место, где EasyMock побеждает. У меня есть два решения для вас, которые не связаны с Mockito. Первый - переопределить methodB в вашем тестовом экземпляре. Другой - частично издеваться над EasyMock:
import org.junit.Test;
import static org.junit.Assert.*;
import static org.easymock.EasyMock.*;
public class PartialMockTest {
class ClassX {
String methodA(String arg) {return methodB(arg);}
String methodB(String arg) {return "toto";}
}
@Test
public void MockitoOnClassX(){
ClassX classx = mock(ClassX.class);
when(classx.methodB("hiyas")).thenReturn("tomtom");
when(classx.methodA(anyString())).thenCallRealMethod();
String response = classx.methodA("hiyas");
assertEquals("tomtom",response);
}
@Test
public void OverrideOnClassX() {
ClassX classx = new ClassX(){@Override String methodB(String arg){return "tomtom";}};
String response = classx.methodA("hiyas");
assertEquals("tomtom",response);
}
@Test
public void PartialMockOnClassX() throws NoSuchMethodException {
ClassX classx = createMockBuilder(ClassX.class).addMockedMethod("methodB").createMock();
expect(classx.methodA("hiyas")).andReturn("tomtom");
replay(classx);
String response = classx.methodA("hiyas");
assertEquals("tomtom",response);
}
}