Смешивание JUnit4 и JUnit5
JUnit — одна из самых популярных сред тестирования для языка программирования Java. Это также сыграло важную роль в разработке Test Driven Development, или TDD. В 2018 году была выпущена последняя версия этой платформы, JUnit5, и многим программистам, использующим платформу JUnit, пришлось решить, следует ли рефакторить свой существующий код, написанный в предыдущей версии JUnit.
‹tl;dr› Эта статья посвящена объединению JUnit4 и JUnit5 в ваш текущий проект, чтобы получить преимущества JUnit5 без рефакторинга всех уже написанных тестов JUnit4. Цель состоит не в том, чтобы подробно описать JUnit5, а в том, чтобы дать рекомендации по переносу поддержки JUnit5.
JUnit5 имеет много преимуществ, которые разработчики захотят использовать. Улучшенная обработка исключений, улучшенные параметризованные тесты, несколько исполнителей тестов и т. д. Если вы похожи на меня и хотите как можно скорее перейти на более новую платформу, вы, вероятно, также знаете, как это больно.
К счастью, JUnit5 имеет очень хорошую поддержку для работы бок о бок с версией 4. Думаю, это важно в проектах, где есть сотни уже написанных тестов. Рефакторинг всех из них — это огромная работа, и гораздо проще отказаться, чем продолжать внедрять что-то новое.
В следующем посте я разбил шаги, которые вам нужно будет выполнить, чтобы внедрить поддержку JUtin5 для тестов, при этом поддерживая тесты JUnit4.
Предположим, у нас есть проект gradle
plugins { id 'java' id 'com.adarshr.test-logger' version '1.6.0' } group 'rainoko' version '1.0-SNAPSHOT' sourceCompatibility = 11 repositories { mavenCentral() } dependencies { testCompile('junit:junit:4.12') } wrapper { gradleVersion = '5.2.1' }
с некоторым простым классом SimpleNaturalCalculator.java
package ee.rainoko.junit5demo; public class SimpleNaturalCalculator { public int addition(int arg1, int arg2) { return arg1 + arg2; } public int substraction(int arg1, int arg2) { return arg1 - arg2; } public int multiplication(int arg1, int arg2) { return arg1 * arg2; } public int division(int arg1, int arg2) { return arg1 / arg2; } }
И покрыт тестом SimpleNaturalCalculatorTest.java
package ee.rainoko.junit5demo; import org.junit.*; import static org.junit.Assert.*; public class SimpleNaturalCalculatorJunit4Test { @Test public void shouldAdd() { SimpleNaturalCalculator calculator = new SimpleNaturalCalculator(); int result = calculator.addition(1, 2); assertEquals(3, result); } @Test public void shouldSubstract() { SimpleNaturalCalculator calculator = new SimpleNaturalCalculator(); int result = calculator.substraction(1, 2); assertEquals(-1, result); } @Test public void shouldMultiply() { SimpleNaturalCalculator calculator = new SimpleNaturalCalculator(); int result = calculator.multiplication(1, 2); assertEquals(2, result); } @Test public void shouldDivide() { SimpleNaturalCalculator calculator = new SimpleNaturalCalculator(); int result = calculator.division(1, 2); assertEquals(0, result); } }
Как мы видим, это тест JUnit4 с использованием аннотаций из org.junit.
Давайте запустим это с помощью следующей команды:
gradlew test
И получаем такой результат:
ee.rainoko.junit5demo.SimpleNaturalCalculatorTest Test shouldAdd PASSED Test shouldDivide PASSED Test shouldSubstract PASSED Test shouldMultiply PASSED
Сейчас мы настраиваем стандартный проект с JUnit4.
Давайте продолжим. Наша цель — внедрить поддержку JUnit5. В отличие от версии 4, версия 5 имеет модульную структуру библиотеки: [https://junit.org/junit5/docs/current/user-guide/]
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
Платформа JUnit служит основой для запуска сред тестирования на JVM. [https://junit.org/junit5/docs/current/user-guide/]
JUnit Jupiter — это комбинация новой модели программирования и модели расширений для написания тестов и расширений в JUnit 5. [https://junit.org/junit5/docs/current/user- руководство/]
JUnit Vintage предоставляет TestEngine
для запуска тестов на основе JUnit 3 и JUnit 4 на платформе.[https://junit.org/junit5/docs/current/user-guide/]
Теперь, зная это, давайте добавим поддержку JUnit5. Для начала, чтобы избежать путаницы, давайте переименуем наш тестовый класс junit4 в SimpleNaturalCalculatorJunit4Test.java.
Давайте добавим зависимости JUnit5 в gradle.
// JUnit Jupiter testImplementation('org.junit.jupiter:junit-jupiter:5.4.0') // JUnit Vintage testCompileOnly('junit:junit:4.12') testRuntimeOnly('org.junit.vintage:junit-vintage-engine:5.4.0') { because 'allows JUnit 3 and JUnit 4 tests to run' }
Как видите, мы добавили junit-jupiter. Также отмечен junit:4.12 как testCompileOnly. Эта библиотека по-прежнему необходима для компиляции, если мы хотим использовать наши старые тесты junit4 без каких-либо изменений. А затем мы также добавили junit-vintage-engine, чтобы платформа junit могла запускать тесты JUnit4 параллельно с тестами JUnit5.
Наконец, нам нужно добавить также команду для использования платформы JUnit5 для запуска тестов в gradle.
test { useJUnitPlatform() }
Нет, давайте добавим тестовый класс JUnit5SimpleNaturalCalculatorJunit5Test.java
package ee.rainoko.junit5demo; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; class SimpleNaturalCalculatorJunit5Test { @Test void shouldAdd() { SimpleNaturalCalculator calculator = new SimpleNaturalCalculator(); int result = calculator.addition(1, 2); assertEquals(3, result); } @Test void shouldSubstract() { SimpleNaturalCalculator calculator = new SimpleNaturalCalculator(); int result = calculator.substraction(1, 2); assertEquals(-1, result); } @Test void shouldMultiply() { SimpleNaturalCalculator calculator = new SimpleNaturalCalculator(); int result = calculator.multiplication(1, 2); assertEquals(2, result); } @Test void shouldDivide() { SimpleNaturalCalculator calculator = new SimpleNaturalCalculator(); int result = calculator.division(1, 2); assertEquals(0, result); } }
Как вы можете подтвердить из импорта, теперь мы используем junit jupiter. Обратите внимание, что тестовый класс защищен пакетом, как и методы. JUnit5 теперь позволяет нам использовать модификаторы package-protected, что, как мне кажется, лучше раскрывает назначение модификаторов доступа java.
Давайте запустим наши тесты
gradlew test
И у нас есть выход
ee.rainoko.junit5demo.SimpleNaturalCalculatorJunit4Test Test shouldAdd PASSED Test shouldDivide PASSED Test shouldSubstract PASSED Test shouldMultiply PASSED ee.rainoko.junit5demo.SimpleNaturalCalculatorJunit5Test Test shouldAdd() PASSED Test shouldDivide() PASSED Test shouldSubstract() PASSED Test shouldMultiply() PASSED
Мы можем даже использовать смешанный тестовый класс.
package ee.rainoko.junit5demo; import static org.junit.jupiter.api.Assertions.assertEquals; public class SimpleNaturalCalculatorJunitMixedTest { @org.junit.Test public void shouldAddJunit4() { SimpleNaturalCalculator calculator = new SimpleNaturalCalculator(); int result = calculator.addition(1, 2); org.junit.Assert.assertEquals(3, result); org.junit.jupiter.api.Assertions.assertEquals(3, result); } @org.junit.jupiter.api.Test void shouldAddJunit5() { SimpleNaturalCalculator calculator = new SimpleNaturalCalculator(); int result = calculator.addition(1, 2); org.junit.Assert.assertEquals(3, result); org.junit.jupiter.api.Assertions.assertEquals(3, result); } @org.junit.Test public void shouldSubstractJunit4() { SimpleNaturalCalculator calculator = new SimpleNaturalCalculator(); int result = calculator.substraction(1, 2); assertEquals(-1, result); } @org.junit.jupiter.api.Test void shouldSubstractJunit5() { SimpleNaturalCalculator calculator = new SimpleNaturalCalculator(); int result = calculator.substraction(1, 2); assertEquals(-1, result); } @org.junit.Test public void shouldMultiplyJunit4() { SimpleNaturalCalculator calculator = new SimpleNaturalCalculator(); int result = calculator.multiplication(1, 2); assertEquals(2, result); } @org.junit.jupiter.api.Test void shouldMultiplyJunit5() { SimpleNaturalCalculator calculator = new SimpleNaturalCalculator(); int result = calculator.multiplication(1, 2); assertEquals(2, result); } @org.junit.Test public void shouldDivideJunit4() { SimpleNaturalCalculator calculator = new SimpleNaturalCalculator(); int result = calculator.division(1, 2); assertEquals(0, result); } @org.junit.jupiter.api.Test void shouldDivideJunit5() { SimpleNaturalCalculator calculator = new SimpleNaturalCalculator(); int result = calculator.division(1, 2); assertEquals(0, result); } }
Как видите, теперь у нас есть аннотации от org.junit и от org.junit.jupiter.api. Платформа JUnit5 выбирает правильный движок для каждого метода тестирования.
Вы даже можете смешивать утверждения из старого пакета JUnit4 и нового пакета JUnit5 в любом типе теста.
gradlew test
И получаем вывод
ee.rainoko.junit5demo.SimpleNaturalCalculatorJunit4Test Test shouldAdd PASSED Test shouldDivide PASSED Test shouldSubstract PASSED Test shouldMultiply PASSED ee.rainoko.junit5demo.SimpleNaturalCalculatorJunitMixedTest Test shouldAddJunit4 PASSED Test shouldDivideJunit4 PASSED Test shouldMultiplyJunit4 PASSED Test shouldSubstractJunit4 PASSED ee.rainoko.junit5demo.SimpleNaturalCalculatorJunit5Test Test shouldAdd() PASSED Test shouldDivide() PASSED Test shouldSubstract() PASSED Test shouldMultiply() PASSED ee.rainoko.junit5demo.SimpleNaturalCalculatorJunitMixedTest Test shouldAddJunit5() PASSED Test shouldDivideJunit5() PASSED Test shouldMultiplyJunit5() PASSED Test shouldSubstractJunit5() PASSED SUCCESS: Executed 16 tests in 1s
Учтите, что JUnit4 и JUnit5 имеют разные аннотации @Before…. Если вам нужно смешать их, добавьте обе аннотации к вашим методам setUp и tearDown.
Надеюсь, что эта статья поможет перейти на JUnit5, даже если ваш проект активно использует тесты JUnit4, и получить преимущества сейчас, а не завтра.
Читать далее
Есть много хороших примеров и статей о JUnit5. Прочтите их также