Окончательный метод издевательств
Мне нужен mock некоторый класс с окончательным методом, используя mockito. Я написал что-то вроде этого
@Test
public void test() {
B b = mock(B.class);
doReturn("bar called").when(b).bar();
assertEquals("must be \"overrided\"", "bar called", b.bar());
//bla-bla
}
class B {
public final String bar() {
return "fail";
}
}
Но это терпит неудачу.
Я попробовал "взломать", и он работает.
@Test
public void hackTest() {
class NewB extends B {
public String barForTest() {
return bar();
}
}
NewB b = mock(NewB.class);
doReturn("bar called").when(b).barForTest();
assertEquals("must be \"overrided\"", "bar called", b.barForTest());
}
Он работает, но "пахнет".
Итак, Где правильный путь?
Спасибо.
Ответы
Ответ 1
В Mockito нет поддержки для издевательства окончательных методов.
Как сказал Джон Скит, вы должны искать способ избежать зависимости от конечного метода. Тем не менее, есть некоторые способы выхода из управления байт-кодом (например, с помощью PowerMock)
A сравнение между Mockito и PowerMock подробно объяснит.
Ответ 2
Из Часто задаваемые вопросы по Mockito:
Каковы ограничения Mockito
- Невозможно высмеять окончательные методы - их реальное поведение выполняется без каких-либо исключений. Мокито не может предупредить вас о насмешливых окончательных методах, поэтому будьте бдительны.
Ответ 3
Вы можете использовать Powermock вместе с Mockito, тогда вам не нужно подклассы B.class. Просто добавьте это в начало тестового класса
@RunWith(PowerMockRunner.class)
@PrepareForTest(B.class)
@PrepareForTest
инструктирует Powermock использовать инструмент B.class, чтобы сделать окончательный и статический методы макетными. Недостатком такого подхода является то, что вы должны использовать PowerMockRunner, который исключает использование других тестовых бегунов, таких как тестовый бегун Spring.
Ответ 4
Mockito 2 теперь поддерживает издевательские окончательные методы, но это функция "инкубации". Для его активации требуются некоторые шаги, которые описаны здесь:
https://github.com/mockito/mockito/wiki/What's-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking -of-конечная-classesmethods
Ответ 5
Предполагая, что класс B выглядит следующим образом:
class B {
private String barValue;
public final String bar() {
return barValue;
}
public void final setBar(String barValue) {
this.barValue = barValue;
}
}
Существует лучший способ сделать это без использования инфраструктуры PowerMockito.
Вы можете создать SPY для своего класса и можете высмеять ваш окончательный метод.
Ниже приведен способ сделать это:
@Test
public void test() {
B b = new B();
b.setBar("bar called") //This should the expected output:final_method_bar()
B spyB = Mockito.spy(b);
assertEquals("bar called", spyB.bar());
}
Ответ 6
Я просто сделал то же самое. Мое дело было в том, что я хотел убедиться, что метод не вызвал ошибку "Причина", но поскольку это метод catch/log/return, я не мог проверить его напрямую, не изменяя класс.
Я хотел просто высмеять регистратор, в который я прошел, но что-то насчет насмешки интерфейса "Журнал", похоже, не работает, и издевательство над классом типа SimpleLog не работает, потому что эти методы являются окончательными.
В итоге я создал анонимный внутренний класс, расширяющий SimpleLog, который перегружает метод "log (level, string, error)" базового уровня, который остальные все делегируют, а затем просто ждет вызова с "уровнем" 5.
В общем, расширение класса для поведения на самом деле не плохая идея, может быть предпочтительнее насмехаться, если это не слишком сложно.
Ответ 7
Mockito 2.x теперь поддерживает финальный метод и заключительную классовую заглушку.
Из документов:
Насмешка над финальными уроками и методами - инкубационная функция. Эту функцию нужно явно активировать, создав файл src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
содержащий одну строку:
mock-maker-inline
После создания этого файла вы можете сделать:
final class FinalClass {
final String finalMethod() { return "something"; }
}
FinalClass concrete = new FinalClass();
FinalClass mock = mock(FinalClass.class);
given(mock.finalMethod()).willReturn("not anymore");
assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());
На последующих этапах команда представит программный способ использования этой функции. Мы определим и предоставим поддержку для всех немыслимых сценариев.