Подтвердить что ты не робот

JUNIT: запуск установки только один раз для большого количества тестовых классов

У меня есть класс, который я использую в качестве основы для своих модульных тестов. В этом классе я инициализирую всю среду для своих тестов, настройки сопоставлений базы данных, ввода нескольких записей базы данных в нескольких таблицах и т.д. У этого класса есть метод с аннотацией @BeforeClass, который выполняет инициализацию. Далее, я расширяю этот класс с помощью определенных классов, в которых у меня есть методы @Test.

Мой вопрос в том, что, поскольку класс before для всех этих тестовых классов точно такой же, как я могу обеспечить, чтобы они выполнялись только один раз для всех тестов. Одно простое решение состоит в том, что я мог бы держать все тесты в одном классе. Тем не менее, количество тестов огромно, также они классифицируются на основе функциональных головок. Поэтому они расположены в разных классах. Однако, поскольку они нуждаются в той же самой настройке, они наследуют @BeforeClass. В результате вся настройка выполняется не реже одного раза в тестовом классе, и занимает гораздо больше времени, чем я бы предпочел.

Я мог бы, однако, разместить их в разных подпакетах под одним пакетом, поэтому, если есть способ, как я могу запустить настройку один раз для всех тестов внутри этого пакета, было бы здорово.

4b9b3361

Ответ 1

С набором тестов JUnit4 вы можете сделать что-то вроде этого:

@RunWith(Suite.class)
@Suite.SuiteClasses({ Test1IT.class, Test2IT.class })
public class IntegrationTestSuite
{
    @BeforeClass
    public static void setUp()
    {
        System.out.println("Runs before all tests in the annotation above.");
    }

    @AfterClass
    public static void tearDown()
    {
        System.out.println("Runs after all tests in the annotation above.");
    }
}

Затем вы запускаете этот класс, как если бы вы запускали обычный тестовый класс, и он будет запускать все ваши тесты.

Ответ 2

JUnit не поддерживает это, вам придется использовать стандартные рабочие среды Java для одиночных игр: переместите общий код установки в статический блок кода, а затем вызовите пустой метод в этом классе:

 static {
     ...init code here...
 }

 public static void init() {} // Empty method to trigger the execution of the block above

Убедитесь, что все тесты вызывают init(), например, я помещаю его в метод @BeforeClass. Или поместите статический кодовый блок в общий базовый класс.

В качестве альтернативы используйте глобальную переменную:

 private static boolean initialize = true;
 public static void init() {
     if(!initialize) return;
     initialize = false;

     ...init code here...
 }

Ответ 3

Создайте один базовый класс для всех тестов:

public class BaseTest {
    static{
        /*** init code here ***/
    }   
}

и каждый тест должен наследовать от него:

public class SomeTest extends BaseTest {

}

Ответ 5

Не уверен, что кто-то все еще использует JUnit и пытается его исправить, не используя Spring Интегрирование Runner (aka no Spring). TestNG имеет эту функцию. Но вот решение на основе JUnit.

Создайте операцию RunOnce для потока, например. Это поддерживает список классов, для которых была выполнена операция.

public class RunOnceOperation {
private static final ThreadLocal t = new ThreadLocal();

public void run(Function f) {
    if (t.get() == null) {
        t.set(Arrays.asList(getClass()));
        f.apply(0);
    } else {
        if (!((List) t.get()).contains(getClass())) {
            ((List) t.get()).add(getClass());
            f.apply(0);
        }
    }
  }
}

Вернитесь в unit test

@Before
public beforeTest() {
    operation.run(new Function<Integer, Void>() {
        @Override
        public Void apply(Integer t) {
            checkBeanProperties();
            return null;
        }
    });
}

private void checkBeanProperties() {
   //I only want to check this once per class.
   //Also my bean check needs instance of the class and can't be static.
}


My function interface is like this:

interface Function<I,O> {
 O apply(I i); 
}

Когда вы используете этот способ, вы можете выполнять операции один раз в классе с помощью ThreadLocal.