Написание тестов JUnit с помощью @BeforeClass @Before in Suites - PullRequest
0 голосов
/ 16 октября 2018

Я использую JUnit 4 для тестирования серверной системы с базой данных в памяти.Я использую @ BeforeClass @ До @ После и @AfterClass.

До сих пор отлично работаетуровень класса.

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

@ Before просто вытирает планшет для следующего теста.Это довольно быстро.

Мои тесты выглядят примерно так:

class CompanyTest  {

    @BeforeClass
    public static void beforeAll() throws Exception {
        BeforeAll.run(); //Setup In Memory Database!!! Very time intensive!!!
    }
    @Before
    public void beforeTest() throws Exception {
        BeforeTest.run(); //Setup data in database. Relatively quick
    }


    @Test
    public void testCreateCompany() throws Exception {
        ///...
    }
    @Test
    public void testDeleteCompany() throws Exception {
        ///...
    }
    @Test
    public void testAdminCompany() throws Exception {
        ///...
    }


    @After
    public void afterTest() {
        AfterTest.run(); //clear data
    }
    @AfterClass
    public static void afterAll() throws Exception {
        AfterAll.run(); //tear down database
    }
}

До сих пор отлично работало на уровне класса.

Я могу щелкнуть правой кнопкой мыши (в Eclipse) для отдельного теста, и он будет запускаться @ BeforeClass , а затем @ Before .

Я также могу щелкнуть (в Eclipse) на самом классе, и он будет запускаться @ BeforeClass только один раз, а затем @ Before перед каждым тестом.

.... но как этот принцип распространяется на уровень Suite?

Я хочу запустить @BeforeClass перед всеми моими классами в Suite.Если я напишу свой Suite так:

@Suite.SuiteClasses({ CompanyTest.class, CustomerTest.class, SomeOtherTest.class, })

public class AllTests {

    @BeforeClass
    public static void beforeAll() throws Exception {
        BeforeAll.run();
    }

    @AfterClass
    public static void afterAll() throws Exception {
        AfterAll.run();
    }
}

... Мне нужно удалить @BeforeClass из всех моих тестовых классов.Это раздражает, потому что у меня много тестовых классов, и я не хочу удалять свой @BeforeClass, потому что я хочу тестировать их индивидуально.

В основном я говорю:

Существует ли простой способ (щелчок мыши в IDE) для тестирования тестов JUnit на (a) уровне метода, (b) уровне класса и (c) уровне комплекта, сохраняя при этом процессы setUp и tearDown уровня сеанса

Ответы [ 2 ]

0 голосов
/ 16 октября 2018

Что вам требуется, так это то, что глобальное состояние управляется через разные точки входа.В вашем классе BeforeAll или AfterAll вы можете хранить статическую ссылку, то есть AtomicBoolean, чтобы отслеживать, выполняли ли вы ее уже или нет.

Проблема теперь - с двумя отдельными классами для beforeAll и afterAll - какой класс должен отвечать за этот флаг.

Поэтому я предлагаю вам определить Ruleон содержит всю логику установки и разборки (в основном весь код BeforeAll и AfterAll) и управляет глобальным состоянием для отслеживания инициализации.

В основном что-то вроде

class MyRule implements TestRule {
    static final AtomicBoolean INITIALIZED = new AtomicBoolean();

    @Override
    public Statement apply(final Statement base, final Description description) {

        return new Statement() {

            @Override
            public void evaluate() throws Throwable {
                boolean needsTearDown = false;
                try {
                    if (INITIALIZED.compareAndSet(false, true)) {
                        BeforeAll.run();
                        needsTearDown = true;
                    }
                    base.evaluate();
                } finally {
                    if (needsTearDown) {
                        AfterAll.run();
                        INITIALIZED.set(false);
                    }
                }
            }
        };
    }
}

И вваш тест и набор просто добавьте

class YourTestOrSuite {

  @ClassRule
  public static MyRule rule = new MyRule();
}
0 голосов
/ 16 октября 2018

Таким образом, у меня есть похожая проблема (инициализация БД, пул соединений, кэшированные данные и т. Д.), Которую необходимо выполнить один раз перед выполнением всех без исключения тестов.Обычно это делается при запуске сервера приложений.Для тестов, которые требуют этого, я добавил базовый класс:

public class BaseInitializedTest {
    private boolean isInitialized;

    @BeforeClass
    public static void init() {
        doOnetimeInit();

        // Do other per unique class initialization here
    }

    private static synchronized void doOnetimeInit() {
        if (!isInitialized) {
            // Do you one time init here

            isInitialized = true;
        }
    }

    @AfterClass
    public static void deinit() {
        // Cleanup
    }
}

И затем мои тесты, которые требуют инициализации:

public class SomethingTest extends BaseInitializedTest {
    @Test
    public testSomething() {
        // Your test here
    }
}

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

...