Повторное использование тестовых реализаций в JUnit 4?
У меня есть интерфейс, например:
public interface Thing {
FrobResult frob(FrobInput);
}
И несколько реализаций этого интерфейса (например, NormalThing
, ImmutableThing
, AsyncThing
), которые я пытаюсь проверить.
Многие из моих методов тестирования действительно касаются обеспечения правильной реализации интерфейса и, таким образом, дублируются в каждой реализации Thing
. В JUnit 3 общим решением для этого было бы создание базового класса (расширение TestCase
), которое затем подклассифицировано каждым классом реализации. Но является ли это правильным подходом для JUnit 4?
Возможные альтернативы в (по-моему) возрастающем порядке предпочтения:
-
Cut'n'paste дублированные методы тестирования. Не СУХОЙ вообще, но я думаю, что менее опасно в тестах, чем в производственном коде.
-
Создайте абстрактный класс с помощью методов @Test
и подкласс для каждого класса тестирования реализации. (Обычно видели с JUnit 3-тестами - это все-таки хороший способ пойти в JUnit 4?)
-
Поместите общие методы тестирования в класс-помощник и вызовите его для каждой реализации. (Состав вместо наследования.)
Какая лучшая практика для № 3? Может быть, тест @RunWith(Parameterized.class)
, который параметризуется при каждой реализации? Или есть лучший способ сделать это?
Ответы
Ответ 1
Да, это правильный подход к созданию базового класса, который затем подклассифицируется каждым классом реализации в JUnit4 тоже.
Я предпочитаю, чтобы базовый тестовый класс для интерфейса был abstract, т.е. ваш "альтернативный" 2, так как я получил хороший опыт в подделке иерархии наследования из производственного кода для тестового кода. Поэтому, если у вас есть интерфейс I
и реализации S1
, S2
и S3
, вы создаете абстрактный тестовый класс TestI
и тестовые классы TestS1
, TestS2
и TestS3
.
Тестовые случаи должны говорить, т.е. рассказывать историю. Выбирая - как всегда - имена методов тщательно и используйте только чистое поведенческое подтипирование, наследование не обфускает это.
Ответ 2
Я использую подход № 2 для JUnit и TestNG тестовых примеров. Это наиболее удобно и легко поддерживать. Его также прямо подбирают (поскольку его родной для OOD является базовый класс, который имеет общие методы).
Для меня классы unit test не отличаются от обычных классов проектов... поэтому я применяю аналогичные соображения дизайна.