Я хотел бы проверить абстрактный класс. Конечно, я могу вручную написать макет, который наследуется от класса.
Могу ли я сделать это, используя фальшивый фреймворк (я использую Mockito) вместо того, чтобы делать макет вручную? Как?
java
unit-testing
mocking
abstract-class
mockito
ripper234
источник
источник
SomeAbstract spy = spy(SomeAbstract.class);
mock(MyAbstractClass.class, withSettings().useConstructor(arg1, arg2).defaultAnswer(CALLS_REAL_METHODS))
Ответы:
Следующее предложение позволяет вам тестировать абстрактные классы без создания «реального» подкласса - Mock является подклассом.
используйте
Mockito.mock(My.class, Mockito.CALLS_REAL_METHODS)
, а затем смоделируйте любые вызываемые абстрактные методы.Пример:
Примечание. Прелесть этого решения в том, что вам не нужно реализовывать абстрактные методы, если они никогда не вызываются.
По моему честному мнению, это лучше, чем использование шпиона, поскольку шпион требует экземпляра, что означает, что вам нужно создать инстанцируемый подкласс вашего абстрактного класса.
источник
Если вам просто нужно протестировать некоторые конкретные методы, не касаясь каких-либо тезисов, вы можете использовать
CALLS_REAL_METHODS
(см . Ответ Мортена ), но если конкретный тестируемый метод вызывает некоторые из рефератов или не реализованные методы интерфейса, это не сработает - Mockito будет жаловаться «Невозможно вызвать реальный метод на интерфейсе Java».(Да, это паршивый дизайн, но некоторые фреймворки, например Tapestry 4, навязывают его вам.)
Обходной путь состоит в том, чтобы полностью изменить этот подход - используйте обычное ложное поведение (т. Е. Все издевается / заглушки) и используйте
doCallRealMethod()
проверяется для явного вызова конкретного тестируемого метода. НапримерОбновлено, чтобы добавить:
Для не пустых методов вам нужно использовать
thenCallRealMethod()
вместо этого, например:В противном случае Mockito будет жаловаться на «Незавершенное обнаружение заглушки».
источник
Вы можете добиться этого с помощью шпиона (хотя используйте последнюю версию Mockito 1.8+).
источник
Фреймворки Mocking предназначены для упрощения моделирования зависимостей класса, который вы тестируете. Когда вы используете макет фреймворка для симуляции класса, большинство фреймворков динамически создают подкласс и заменяют реализацию метода кодом для определения, когда вызывается метод, и возврата поддельного значения.
При тестировании абстрактного класса вы хотите выполнить неабстрактные методы тестируемого субъекта (SUT), поэтому фальшивый фреймворк - это не то, что вам нужно.
Частично путаница заключается в том, что ответ на вопрос, с которым вы связались, говорит о том, чтобы изготовить ручной макет, исходящий из вашего абстрактного класса. Я бы не назвал такой класс насмешкой. Макет - это класс, который используется в качестве замены зависимости, запрограммирован с ожиданиями и может быть запрошен, чтобы увидеть, удовлетворяются ли эти ожидания.
Вместо этого я предлагаю определить неабстрактный подкласс вашего абстрактного класса в вашем тесте. Если это приводит к слишком большому количеству кода, это может быть признаком того, что ваш класс трудно расширить.
Альтернативное решение состоит в том, чтобы сделать ваш тестовый пример сам по себе абстрактным, с абстрактным методом для создания SUT (другими словами, тестовый пример будет использовать шаблон проектирования Template Template ).
источник
Попробуйте использовать пользовательский ответ.
Например:
Он вернет макет для абстрактных методов и вызовет реальный метод для конкретных методов.
источник
Что действительно вызывает у меня недовольство насчет абстрактных классов, так это тот факт, что ни конструктор по умолчанию YourAbstractClass () не вызывается (отсутствует super () в mock), ни кажется, что в Mockito не существует способа инициализировать свойства mock по умолчанию (например, свойства List) с пустым ArrayList или LinkedList).
Мой абстрактный класс (в основном исходный код класса генерируется) НЕ предоставляет инъекцию установщика зависимостей для элементов списка, а также конструктор, в котором он инициализирует элементы списка (которые я пытался добавить вручную).
Только атрибуты класса используют инициализацию по умолчанию: private List dep1 = new ArrayList; приватный список dep2 = новый ArrayList
Таким образом, НЕТ способа высмеивать абстрактный класс без использования реализации реального объекта (например, определения внутреннего класса в классе модульного теста, переопределения абстрактных методов) и отслеживания реального объекта (который выполняет правильную инициализацию поля).
Жаль, что только PowerMock поможет здесь в дальнейшем.
источник
Предполагая, что ваши тестовые классы находятся в том же пакете (в другом корне исходного кода), что и ваши тестируемые классы, вы можете просто создать макет:
и вызвать методы, которые вы хотите проверить, так же, как и любой другой метод.
Вы должны предоставить ожидания для каждого метода, который вызывается с ожиданием для любых конкретных методов, вызывающих супер-метод - не уверен, как вы это сделаете с Mockito, но я считаю, что это возможно с EasyMock.
Все это делает создание конкретного экземпляра
YouClass
и избавляет вас от необходимости предоставлять пустые реализации каждого абстрактного метода.Кроме того, я часто нахожу полезным реализовать абстрактный класс в моем тесте, где он служит примером реализации, которую я тестирую через открытый интерфейс, хотя это зависит от функциональности, предоставляемой абстрактным классом.
источник
Вы можете расширить абстрактный класс анонимным классом в своем тесте. Например (используя Junit 4):
источник
Mockito позволяет имитировать абстрактные классы с помощью
@Mock
аннотации:Недостатком является то, что его нельзя использовать, если вам нужны параметры конструктора.
источник
Вы можете создать экземпляр анонимного класса, внедрить свои макеты и затем протестировать этот класс.
Имейте в виду, что видимость должна быть
protected
для свойстваmyDependencyService
абстрактного классаClassUnderTest
.источник
PowerMock
Whitebox.invokeMethod(..)
может быть полезен в этом случае.источник