Подтвердить что ты не робот

Как использовать Mockito для подделки защищенного метода?

Im, используя Mockito 1.9.5. Как я издеваюсь над тем, что возвращается из защищенного метода? У меня есть этот защищенный метод...

protected JSONObject myMethod(final String param1, final String param2)
{
…
}

Однако, когда я пытаюсь сделать это в JUnit:

    final MyService mymock = Mockito.mock(MyService.class, Mockito.CALLS_REAL_METHODS);        
    final String pararm1 = "param1";
    Mockito.doReturn(myData).when(mymock).myMethod(param1, param2);

В последней строке появляется ошибка компиляции "Метод myMethod не отображается". Как использовать Mockito для подделки защищенных методов? Я готов обновить свою версию, если это ответ.

4b9b3361

Ответ 1

Это не проблема с Mockito, но с простой старой java. Когда вы вызываете метод, у вас нет видимости. Вот почему это проблема времени компиляции, а не проблема времени выполнения.

Пара вариантов:

  • объявить ваш тест в том же пакете, что и класс издевательства
  • измените видимость метода, если вы можете
  • создать локальный (внутренний) класс, который расширяет насмешливый класс, а затем издевается над этим локальным классом. Поскольку класс будет локальным, у вас будет видимость метода.

Ответ 2

Отвечая на запрос образца кода варианта 3 от ответа Джона Б.:


public class MyClass {
    protected String protectedMethod() {
        return "Can't touch this";
    }
    public String publicMethod() {
        return protectedMethod();
    }
}

@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {

    class MyClassMock extends MyClass {
        @Override
        public String protectedFunction() {
            return "You can see me now!";
        }
    }

    @Mock
    MyClassMock myClass = mock(MyClassMock.class);

    @Test
    public void myClassPublicFunctionTest() {
        when(myClass.publicFunction()).thenCallRealMethod();
        when(myClass.protectedFunction()).thenReturn("jk!");
    }
}

Ответ 3

Джон Б прав, это потому, что метод, который вы пытаетесь протестировать, защищен, это не проблема с Mockito.

Другой вариант, который он перечислил, - использовать отражение, чтобы получить доступ к методу. Это позволит вам избежать изменения метода, который вы тестируете, и не менять шаблон, который вы используете для написания тестов, и где вы храните эти тесты. Я должен был сделать это сам для некоторых тестов, где мне не разрешалось изменять существующую базу кода, которая включала большое количество частных методов, которые необходимо было тестировать в блоке.

Эти ссылки объясняют Reflection и как использовать его очень хорошо, поэтому я буду ссылаться на них, а не копировать:

Ответ 4

WhiteBox.invokeMethod() может быть удобен.

Ответ 5

Вы можете использовать Spring ReflectionTestUtils, чтобы использовать свой класс, как он есть, и без необходимости изменять его только для тестов или переносить его в другой класс.

public class MyService {
    protected JSONObject myProtectedMethod(final String param1, final String param2) {
        return new JSONObject();
    }

    public JSONObject myPublicMethod(final String param1) {
        return new JSONObject();
    }
}

И затем в тесте

@RunWith(MockitoJUnitRunner.class)
public class MyServiceTest {

    @Mock
    private MyService myService;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);

        when(myService.myPublicMethod(anyString())).thenReturn(mock(JSONObject.class));
        when(ReflectionTestUtils.invokeMethod(myService, "myProtectedMethod", anyString(), anyString())).thenReturn(mock(JSONObject.class));
    }

}