Я пытаюсь выполнить предварительную настройку и разборку для набора интеграционных тестов, используя jUnit 4.4 для выполнения тестов. Разборка должна выполняться надежно. У меня есть другие проблемы с TestNG, поэтому я хочу вернуться к jUnit. Какие хуки доступны для выполнения до запуска любых тестов и после завершения всех тестов?
Примечание: мы используем maven 2 для нашей сборки. Я пробовал использовать maven pre-
и post-integration-test
фазы, но если тест не прошел, maven останавливается и не запускается post-integration-test
, что не помогает.
java
testing
junit
integration-testing
бледный
источник
источник
post-integration-test
если тест не пройден. См. Также эту страницу вики .Ответы:
Да, можно надежно запускать методы настройки и удаления до и после любых тестов в наборе тестов. Позвольте мне продемонстрировать в коде:
package com.test; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) @SuiteClasses({Test1.class, Test2.class}) public class TestSuite { @BeforeClass public static void setUp() { System.out.println("setting up"); } @AfterClass public static void tearDown() { System.out.println("tearing down"); } }
Итак, ваш
Test1
класс будет выглядеть примерно так:package com.test; import org.junit.Test; public class Test1 { @Test public void test1() { System.out.println("test1"); } }
... и вы можете себе представить, что это
Test2
похоже. Если вы побежитеTestSuite
, то получите:Итак, вы можете видеть, что установка / удаление выполняется только до и после всех тестов соответственно.
Уловка: это работает, только если вы запускаете набор тестов, а не тестируете Test1 и Test2 как отдельные тесты JUnit. Вы упомянули, что используете maven, а плагин maven surefire любит запускать тесты индивидуально, а не как часть пакета. В этом случае я бы рекомендовал создать суперкласс, который расширяет каждый тестовый класс. Затем суперкласс содержит аннотированные методы @BeforeClass и @AfterClass. Хотя это не так чисто, как описанный выше метод, я думаю, он вам подойдет.
Что касается проблемы с неудачными тестами, вы можете установить maven.test.error.ignore, чтобы сборка продолжалась на неудачных тестах. Это не рекомендуется как постоянная практика, но она должна заставить вас работать до тех пор, пока все ваши тесты не пройдут. Дополнительные сведения см. В документации maven surefire .
источник
Мой коллега предложил следующее: вы можете использовать собственный RunListener и реализовать метод testRunFinished (): http://junit.sourceforge.net/javadoc/org/junit/runner/notification/RunListener.html#testRunFinished(org. junit.runner.Result)
Чтобы зарегистрировать RunListener, просто настройте плагин surefire следующим образом: http://maven.apache.org/surefire/maven-surefire-plugin/examples/junit.html раздел «Использование настраиваемых слушателей и репортеров»
Эта конфигурация также должна выбираться модулем отказоустойчивости. Это отличное решение, потому что вам не нужно указывать наборы, тестовые классы поиска или что-то еще - оно позволяет Maven творить чудеса, ожидая завершения всех тестов.
источник
Вы можете использовать аннотацию @ClassRule в JUnit 4.9+, как я описал в ответе на другой вопрос .
источник
Используя аннотации, вы можете сделать что-то вроде этого:
import org.junit.*; import static org.junit.Assert.*; import java.util.*; class SomethingUnitTest { @BeforeClass public static void runBeforeClass() { } @AfterClass public static void runAfterClass() { } @Before public void setUp() { } @After public void tearDown() { } @Test public void testSomethingOrOther() { } }
источник
Мы тут
источник
Что касается «Примечание: мы используем maven 2 для нашей сборки. Я пробовал использовать этапы тестирования maven до и после интеграции, но, если тест не проходит, maven останавливается и не запускает тест после интеграции. , что бесполезно ".
вместо этого вы можете попробовать отказоустойчивый плагин, я думаю, он имеет возможность гарантировать, что очистка происходит независимо от установки или статуса промежуточного этапа
источник
При условии, что все ваши тесты могут расширять «технический» класс и находятся в одном пакете, вы можете проделать небольшой трюк:
public class AbstractTest { private static int nbTests = listClassesIn(<package>).size(); private static int curTest = 0; @BeforeClass public static void incCurTest() { curTest++; } @AfterClass public static void closeTestSuite() { if (curTest == nbTests) { /*cleaning*/ } } } public class Test1 extends AbstractTest { @Test public void check() {} } public class Test2 extends AbstractTest { @Test public void check() {} }
Имейте в виду, что у этого решения много недостатков:
Для информации: listClassesIn () => Как найти все подклассы данного класса в Java?
источник
Насколько мне известно, в JUnit нет механизма для этого, однако вы можете попробовать создать подкласс Suite и переопределить метод run () версией, которая предоставляет хуки.
источник
Поскольку maven-surefire-plugin не запускает сначала класс Suite, а обрабатывает классы набора и тестирования одинаково, поэтому мы можем настроить плагин, как показано ниже, чтобы включить только классы набора и отключить все тесты. Suite выполнит все тесты.
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.5</version> <configuration> <includes> <include>**/*Suite.java</include> </includes> <excludes> <exclude>**/*Test.java</exclude> <exclude>**/*Tests.java</exclude> </excludes> </configuration> </plugin>
источник
Тогда я думаю, что единственный способ получить нужную вам функциональность - это сделать что-то вроде
import junit.framework.Test; import junit.framework.TestResult; import junit.framework.TestSuite; public class AllTests { public static Test suite() { TestSuite suite = new TestSuite("TestEverything"); //$JUnit-BEGIN$ suite.addTestSuite(TestOne.class); suite.addTestSuite(TestTwo.class); suite.addTestSuite(TestThree.class); //$JUnit-END$ } public static void main(String[] args) { AllTests test = new AllTests(); Test testCase = test.suite(); TestResult result = new TestResult(); setUp(); testCase.run(result); tearDown(); } public void setUp() {} public void tearDown() {} }
Я использую что-то подобное в eclipse, поэтому я не уверен, насколько это переносимо за пределами этой среды
источник
Если вы не хотите создавать набор и должны перечислять все свои тестовые классы, вы можете использовать отражение, чтобы найти количество тестовых классов динамически, и обратный отсчет в базовом классе @AfterClass, чтобы выполнить tearDown только один раз:
public class BaseTestClass { private static int testClassToRun = 0; // Counting the classes to run so that we can do the tear down only once static { try { Field field = ClassLoader.class.getDeclaredField("classes"); field.setAccessible(true); @SuppressWarnings({ "unchecked", "rawtypes" }) Vector<Class> classes = (Vector<Class>) field.get(BlockJUnit4ClassRunner.class.getClassLoader()); for (Class<?> clazz : classes) { if (clazz.getName().endsWith("Test")) { testClassToRun++; } } } catch (Exception ignore) { } } // Setup that needs to be done only once static { // one time set up } @AfterClass public static void baseTearDown() throws Exception { if (--testClassToRun == 0) { // one time clean up } } }
Если вы предпочитаете использовать @BeforeClass вместо статических блоков, вы также можете использовать логический флаг для подсчета отражений и настройки теста только один раз при первом вызове. Надеюсь, это кому-то поможет, мне потребовался день, чтобы придумать лучший способ, чем перечисление всех классов в наборе.
Теперь все, что вам нужно сделать, это расширить этот класс для всех ваших тестовых классов. У нас уже был базовый класс, обеспечивающий некоторые общие вещи для всех наших тестов, поэтому это было лучшее решение для нас.
Вдохновение исходит из этого SO-ответа https://stackoverflow.com/a/37488620/5930242
Если вы не хотите расширять этот класс повсюду, этот последний ответ SO может сделать то, что вы хотите.
источник