Страницы

Поиск по вопросам

суббота, 28 декабря 2019 г.

Как запускать серию тестов JUnit строго последовательно?

#java #юнит_тесты #junit


Есть серия тестов. Я хочу, чтобы они использовали некоторый разделяемый объект. Первый
тест его вычисляет, второй (и последующие) требуют его для своей работы. Похоже, что
по умолчанию тесты запускаются в раздельных потоках и первый тест не успевает выполниться
к началу второго.

Про @Before знаю, он плохо подходит, хотелось бы точный контроль за выполнением.

Вопрос: как явным образом указать, что все тесты выполняются последовательно?

/** shared object */
Object a;

@Test() //succeeds
public void testFoo() {
    a = foo();
    Assert.assertNotNull(a);
}

@Test()
public void testBar() {
    Assert.assertNotNull(a); //fails
    b = bar(a); //null pointer exception
}

    


Ответы

Ответ 1



В общем - никак. Тесты должны быть независимы друг от дружки. Если они зависят от последовательности запуска - Вы неверно понимаете концепцию юнит тестов. Поэтому, их лучше писать так @Test() //succeeds // в этом тесте тестируется факт создания правильного объекта public void testFoo() { Object a; a = foo(); Assert.assertNotNull(a); // можно проверить другие поля объекта } @Test() public void testBar() { Object a; a = foo(); Assert.assertNotNull(a); //этот тест можно и пропустить, но лучше оставить // а вот тестить поля объекта уже не нужно // а теперь тестим код, который нуждается в этом объекте. b = bar(a); //null pointer exception } Но и эта схема "не очень правильная". В идеале пишут метод, который будет создавать объект и помещают его в @Before или что там предоставляет фреймворк.

Ответ 2



В JUnit есть аннотация @FixMethodOrder. Попробуйте таким образом: @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class SomeTest { @Test public void aTest() { /* your code */ } @Test public void bTest() { /* your code */ } }

Ответ 3



В целом, как уже заметили, это сделать невозможно (да и неправильно будет). Однако, если уж очень сильно хочется, то можно провернуть это через Suite`ы: import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ TestJUnitA.class, TestJUnitB.class }) public class TestSuite { @BeforeClass public static void beforeClass() throws Exception { } @AfterClass public static void afterClass() throws Exception { } } В приведенном примере TestJUnitA-класс выполнится заведомо перед TestJUnitB

Ответ 4



Согласно идеологии, юнит тесты должны быть изолированы друг от друга, каждый тест это независимая единица, те что зависимы друг от друга это уже не совсем юнит тесты. Другой вопрос, что нередко система настолько сложная и запутанная, что не выловить взаимовлияние тестов происходящее на каких то очень низких не подлежащих макетированию уровнях и вычистить взаимодействие на уровне JVM сложно, а играться с ClassLoaders тоже геморно, я для такого сделал маленький мавен плагин Jute, который просто запускает каждый тестовый метод JUnit в отдельном внешнем процессе в "чистой" jvm

Комментариев нет:

Отправить комментарий