Проблемы с набором тестов JUnit 4

У меня проблема с некоторыми тестами JUnit 4, которые я запускаю с набором тестов.

Если я запускаю тесты по отдельности, они работают без проблем, но при запуске в наборе большинство из них, 90% методов тестирования, терпят неудачу с ошибками. Я заметил, что всегда первые тесты работают нормально, а остальные терпят неудачу. Другое дело, что в некоторых тестах методы не выполняются в правильном порядке (отражение не работает должным образом или работает потому, что извлечение методов не обязательно происходит в созданном порядке). Обычно это происходит, если имеется более одного теста с методами с одинаковыми именами. Я попытался отладить некоторые тесты, и кажется, что от строки к следующей значение некоторых атрибутов становится null.

Кто-нибудь знает, в чем проблема, или если поведение "нормально"?

Заранее спасибо.

P.S.: Хорошо, тесты не зависят друг от друга, ни один из них не зависит, и все они имеют @BeforeClass, @Before, @After, @AfterClass, так что между тестами все прояснилось. Тесты работают с базой данных, но база данных очищается перед каждым тестом в @BeforeClass, так что это не должно быть проблемой.

Упрощенный пример:

ТЕСТИРОВАНИЕ:

import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
importy testclasses...;

@RunWith(Suite.class)
@Suite.SuiteClasses({ Test1.class, Test2.class })
public class TestSuiteX {
 @BeforeClass
 public static void setupSuite() { System.out.println("Tests started"); }   
 @AfterClass
 public static void setupSuite() { System.out.println("Tests started"); }   
}

ТЕСТЫ: тесты проверяют функциональность серверного приложения, работающего на Glassfish.

Теперь тесты расширяют базовый класс, который имеет метод @BeforeClass, который очищает базу данных и логины, и метод @AfterClass, который производит только выход из системы. Это не источник проблем, потому что то же самое произошло до введения этого класса.

Класс имеет некоторые общедоступные статические атрибуты, которые не используются в других тестах, и реализует 2 метода управления.

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

Пример тестовых классов:

    imports....

    public class Test1 extends AbstractTestClass {  
    protected static Log log = LogFactory.getLog( Test1.class.getName() );

    @Test
    public void test1_A() throws CustomException1, CustomException2 {

        System.out.println("text");

        creates some entities with the server api.
        deletes a couple of entities with the server api.

        //tests if the extities exists in the database
        Assert.assertNull( serverapi.isEntity(..) );

    }

}

и второй:

public class Test1 extends AbstractTestClass {

    protected static Log log = LogFactory.getLog( Test1.class.getName() );

    private static String keyEntity;
    private static EntityDO entity;

    @Test
    public void test1_B() throws CustomException1, CustomException2 {

        System.out.println("text");

        creates some entities with the server api, adds one entities key to the static attribute and one entity DO to the static attribute for the use in the next method.
        deletes a couple of entities with the server api.

        //tests if the extities exists in the database
        Assert.assertNull( serverapi.isEntity(..) );

    }

    @Test
    public void test2_B() throws CustomException1, CustomException2 {

        System.out.println("text");

        deletes the 2 entities, the one retrieved by the key and the one associated with the static DO attribute

        //tests if the deelted entities exists in the database
        Assert.assertNull( serverapi.isEntity(..) );

    }

Это базовый пример, настоящие тесты более сложны, но я пробовал использовать упрощенные тесты, но они все равно не работают. Спасибо.


person Hypnus    schedule 11.06.2010    source источник
comment
Можете ли вы опубликовать пример одного из ваших тестов и объяснить, как вы запускаете набор тестов, пожалуйста.   -  person Mark Pope    schedule 11.06.2010
comment
Набор тестов представляет собой набор тестов JUnit 4, в нем есть все настройки тестовых классов и есть @BeforeClass и @AfterClass, которые содержат только некоторую второстепенную информацию (основные строки).   -  person Hypnus    schedule 11.06.2010
comment
опубликованный вами код пропускает наиболее важные детали: 1) AbstractTestClass, 2) методы @BeforeClass, @Before, @After, @AfterClass, 3) как и когда инициализируются keyEntity и entity, 4) какой тест не проходит и как именно ?   -  person Péter Török    schedule 11.06.2010


Ответы (3)


Ситуация, которую вы описываете, звучит как побочная проблема. Вы упомянули, что тесты отлично работают изолированно, но зависят от порядка операций: обычно это критический симптом.

Частью проблемы настройки целого набора тестовых случаев является проблема обеспечения того, чтобы каждый тест начинался с чистого состояния, выполнял свое тестирование, а затем очищался после себя, возвращая все обратно в чистое состояние.

Имейте в виду, что бывают ситуации, когда стандартных процедур очистки (например, @Before и @After) недостаточно. Одна проблема, с которой я столкнулся некоторое время назад, заключалась в наборе тестов баз данных: я добавлял записи в базу данных как часть теста, и мне нужно было специально удалить записи, которые я только что добавил.

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

person Bob Cross    schedule 11.06.2010

Похоже, вы построили свой набор тестов, исходя из предположения, что порядок выполнения методов фиксирован. Это неправильно — JUnit не гарантирует порядок выполнения тестовых методов, поэтому рассчитывать на это не стоит.

Так задумано — модульные тесты должны быть полностью независимы друг от друга. Чтобы гарантировать это, JUnit создает отдельный новый экземпляр вашего тестового класса для выполнения каждого тестового метода. Таким образом, любые атрибуты, которые вы установили в одном методе, будут потеряны в следующем.

Если у вас есть общий код настройки/разборки тестов, вы должны поместить его в отдельные методы, аннотированные @Before/@After. Они выполняются до и после каждого метода тестирования.

Обновление: вы написали

база данных очищается перед каждым тестом в @BeforeClass

если это не опечатка, это может быть источником ваших проблем. Очищать БД нужно в методе @Before - @BeforeClass запускается только один раз для каждого класса.

person Péter Török    schedule 11.06.2010
comment
Хорошо, тесты не зависят друг от друга, но их методы зависят друг от друга, поэтому я не могу поместить код очистки базы данных в метод @Before, потому что тогда он будет очищать базу данных перед каждым методом, и он не будет работать. Если вы думаете, что я поместил код очистки базы данных в @BeforeClass пакета, это не так. Спасибо. - person Hypnus; 11.06.2010
comment
@Hypnus, то, что вы называете тестом выше, является тестовым классом, верно? Видимо, у нас тут терминологическое несоответствие. Тестовый класс может содержать множество тестовых методов. Каждый метод представляет собой отдельный тест на языке модульного тестирования. И эти тесты, то есть методы тестирования, не должны зависеть друг от друга. - person Péter Török; 11.06.2010

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

Возможно, мы сможем помочь более конкретно, если вы опубликуете упрощенный пример того, что происходит не так.

person Eric Wilson    schedule 11.06.2010
comment
Спасибо, я сделаю, но через 2 часа у меня есть срочная работа. - person Hypnus; 11.06.2010
comment
Я добавил упрощенный пример для моего случая. Я попытался запустить тесты непосредственно с помощью JUnit в пакете, и все равно не работает (тогда некоторые методы терпят неудачу в разных местах). Спасибо. - person Hypnus; 11.06.2010