Я пытаюсь выполнить предварительную настройку и разборку для набора интеграционных тестов, используя jUnit 4.4 для выполнения тестов. Разборка должна выполняться надежно. У меня есть другие проблемы с TestNG, поэтому я хочу вернуться к jUnit. Какие хуки доступны для выполнения перед запуском любых тестов и после завершения всех тестов?
Примечание: мы используем maven 2 для нашей сборки. Я пробовал использовать фазы maven pre- и post-integration-test, но, если тест не прошел, maven останавливается и не запускает post-integration-test, что не помогает.
не могли бы вы поделиться своей окончательной реализацией?




Насколько мне известно, в JUnit нет механизма для этого, однако вы можете попробовать создать подкласс Suite и переопределить метод run () версией, которая предоставляет хуки.
Используя аннотации, вы можете сделать что-то вроде этого:
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()
{
}
}
Настройку и разборку необходимо выполнять один раз за запуск. Это поможет, только если все тесты будут в одном классе.
Это настраивает только отдельный набор тестов, а не весь этап тестирования.
Тогда я думаю, что единственный способ получить нужную вам функциональность - это сделать что-то вроде
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, поэтому я не уверен, насколько он переносим за пределами этой среды
Это пример для JUnit3, и OP запросил JUnit4, но на всякий случай некоторые пользователи JUnit3 найдут этот вопрос ... Для JUnit3 было бы лучше избавиться от метода main () и использовать метод suite () оберните TestSuite в подкласс junit.extensions.TestSetup. У вас все еще есть те же предостережения, что и в примере Джули, о запуске отдельных тестовых классов в вашей среде IDE.
Да, можно надежно запускать методы установки и удаления до и после любых тестов в наборе тестов. Позвольте мне продемонстрировать в коде:
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, вы получите:
setting up
test1
test2
tearing down
Таким образом, вы можете видеть, что установка / удаление выполняется только до и после всех тестов соответственно.
Уловка: это работает, только если вы запускаете набор тестов, а не тестируете Test1 и Test2 как отдельные тесты JUnit. Вы упомянули, что используете maven, а плагин maven surefire любит запускать тесты индивидуально, а не как часть пакета. В этом случае я бы рекомендовал создать суперкласс, который расширяет каждый тестовый класс. Затем суперкласс содержит аннотированные методы @BeforeClass и @AfterClass. Хотя это не так чисто, как описанный выше метод, я думаю, что он вам подойдет.
Что касается проблемы с неудачными тестами, вы можете установить maven.test.error.ignore, чтобы сборка продолжалась на неудачных тестах. Это не рекомендуется как постоянная практика, но она должна помочь вам работать до тех пор, пока все ваши тесты не пройдут. Подробнее см. документация maven surefire.
Это отлично сработало для меня, когда я вошел в maven-surefire-plugin и создал список включений, указывающий на набор, который я хотел запустить.
Начиная с JUnit 4.8.2, это не очень хорошо работает с параметризованными тестами. Методы @BeforeClass Suite будут запускаться после как метод @ Parameterized.Parameters теста, предотвращая любую зависимость от настройки Suite.
В ответ на мой ответ при использовании @Theories вызов метода @DataPoints - это вызов после @BeforeClass из Suite.
Извините за некро, но добавление BeforeClass / AfterClass к суперклассу не работает должным образом - они по-прежнему вызываются после завершения каждого тестового класса. Это для потомков.
Это все еще актуальный подход? Как избежать необходимости перечислять список тестовых классов в аннотации SuiteClasses?
@SubuSankaraSubramanian см. Этот ответ: stackoverflow.com/a/28606190/363573
Мы тут
Поскольку 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>
Что касается "Примечание: мы используем 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?
Это не так, как показывают мои собственные тесты. У меня есть суперкласс, который запускает встроенную стеклянную рыбку на beforeclass и выключает ее после урока. У меня есть 2 класса, которые расширяют этот суперкласс. Класс before выполняется перед запуском тестов, определенных в каждом классе.
Вы можете использовать Аннотации @ClassRule в JUnit 4.9+ как Я в ответе описал другой вопрос.
Мой коллега предложил следующее: вы можете использовать собственный 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 творить чудеса, ожидая завершения всех тестов.
+1 Это первое пригодное для использования решение, которое я видел без громоздкого обслуживания класса Suites!
Если вы не хотите создавать набор и должны перечислять все свои тестовые классы, вы можете использовать отражение, чтобы найти количество тестовых классов динамически, и обратный отсчет в базовом классе @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 может сделать то, что вы хотите.
Для интеграционных тестов вы должны использовать maven-failsafe-plugin вместо surefire. Это не пропустит
post-integration-test, если тест не пройден. См. Также эта страница вики.