Юнит-тестирование с 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);
    }

}
Другие вопросы по тегам