Хук выполнения до и после Suite в jUnit 4.x - PullRequest
81 голосов
/ 17 сентября 2008

Я пытаюсь предварительно настроить и разорвать набор интеграционных тестов, используя jUnit 4.4 для выполнения тестов. Разборка должна выполняться надежно. У меня другие проблемы с TestNG, поэтому я пытаюсь портировать обратно на jUnit. Какие хуки доступны для выполнения до запуска любых тестов и после их завершения?

Примечание: мы используем maven 2 для нашей сборки. Я пытался использовать фазы pre- & post-integration-test maven, но если тест не пройден, maven останавливается и не запускает post-integration-test, что не поможет

Ответы [ 11 ]

109 голосов
/ 07 октября 2008

Да, можно надежно запускать методы настройки и завершения до и после любых тестов в наборе тестов. Позвольте мне продемонстрировать в коде:

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 верный .

31 голосов
/ 07 февраля 2013

Мой коллега предложил следующее: вы можете использовать собственный 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 раздел "Использование пользовательских слушателей и репортеров"

Эта конфигурация также должна выбираться плагином failsafe. Это отличное решение, потому что вам не нужно указывать наборы, классы тестов поиска или что-либо еще - оно позволяет Maven творить чудеса, ожидая завершения всех тестов.

11 голосов
/ 03 октября 2011

Вы можете использовать аннотацию @ ClassRule в JUnit 4.9 + как Я описал в ответе другой вопрос .

7 голосов
/ 17 сентября 2008

Используя аннотации, вы можете сделать что-то вроде этого:

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()
    {

    }

}
3 голосов
/ 01 апреля 2009

Здесь мы

  • обновлён до JUnit 4.5,
  • написал аннотации для обозначения каждого тестового класса или метода, который нуждался в работающем сервисе,
  • написал обработчики для каждой аннотации, которые содержали статические методы для реализации установки и демонтажа службы,
  • расширен обычный Runner для поиска аннотаций в тестах, добавив методы статического обработчика в цепочку выполнения теста в соответствующих точках.
2 голосов
/ 27 сентября 2011

При условии, что все ваши тесты могут расширять «технический» класс и находиться в одном пакете, вы можете сделать небольшую хитрость:

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() {}
}

Имейте в виду, что у этого решения есть много недостатков:

  • должен выполнить все тесты пакета
  • должен подкласс класса "techincal"
  • вы не можете использовать @BeforeClass и @AfterClass внутри подклассов
  • если вы выполняете только один тест в пакете, очистка не выполняется
  • ...

Для информации: listClassesIn () => Как найти все подклассы данного класса в Java?

2 голосов
/ 07 декабря 2010

Что касается «Примечание: мы используем maven 2. для нашей сборки. Я пробовал использовать этапы maven до и после тестирования интеграции, но, если тест не пройден, maven останавливается и не запускается после интеграционный тест, который не помогает. "

вместо этого вы можете попробовать подключаемый модуль failsafe, я думаю, что он имеет возможность гарантировать очистку независимо от состояния установки или промежуточной стадии

0 голосов
/ 26 октября 2016

Если вы не хотите создавать набор и должны перечислять все ваши тестовые классы, вы можете использовать отражение, чтобы динамически найти количество тестовых классов и вести обратный отсчет в базовом классе @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-ответ может сделать то, что вы хотите.

0 голосов
/ 23 июня 2010

Поскольку maven-surefire-plugin не запускает сначала класс Suite, а обрабатывает классы suite и test, мы можем настроить плагин, как показано ниже, для включения только классов 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>
0 голосов
/ 17 сентября 2008

Я думаю, что единственный способ получить нужную функциональность - это сделать что-то вроде

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, поэтому я не уверен, насколько он переносим за пределами этой среды

...