С jUnit 4 можно ли параметризовать @BeforeClass?

Я использую jUnit для управления интеграционными тестами для приложения, которое обращается к базе данных. Поскольку настройка тестовых данных - это трудоемкая операция, я делаю это в методе @BeforeClass, который выполняется только один раз для каждого тестового класса (в отличие от метода @Before, который запускается один раз для каждого метода тестирования).

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

Несколько вопросов,

Вызывает ли Parameterized метод @BeforeClass для каждой перестановки параметров или вызывает ли он только один раз?

Если метод @BeforeClass вызывается повторно, есть ли способ получить доступ к значениям параметров изнутри?

Если ни один из них, что люди считают лучшим альтернативным подходом к этой проблеме?

Ответы

Ответ 1

Я думаю, вам понадобится пользовательский тестовый бегун. У меня та же проблема, с которой вы сталкиваетесь (нужно запускать те же тесты с использованием нескольких дорогостоящих конфигураций). Вам понадобится способ параметризации настройки, возможно, используя аннотации @Parameter, аналогичные тем, которые используются параметризуемым бегуном, но по статическим полям-членам вместо полей экземпляра. Пользовательский бегун должен будет найти все статические поля-члены с аннотацией @Parameter, а затем запустить тестовый класс (возможно, используя базовый BlockJunit4ClassRunner) один раз в статическом поле @Parameter. Поле @Parameter должно быть @ClassRule.

Andy on Software отлично поработала над созданием пользовательских тестовых бегунов, и он так ясно объясняет эти сообщения в блоге здесь и здесь.

Ответ 2

@BeforeClass вызывается только один раз в вашем примере. Что имеет смысл, учитывая имя - перед классом!

Если ваши тесты требуют разных данных, есть два варианта, о которых я могу думать:

  • Настройте эти данные в @Before так, чтобы они были специфичны для тестирования
  • Группируйте тесты, которые вы хотите запускать с одними и теми же данными, в отдельные классы тестов и используйте @BeforeClass для каждого из них.

Ответ 3

Вы можете вызвать эту логику инициализации в конструкторе вашего тестового класса. Следите за последним параметром, используемым в статической переменной. Когда он изменится, настройте класс для нового параметра.

Я не могу придумать эквивалент для AfterClass.

Ответ 4

Это старый вопрос, но мне просто пришлось решить, вероятно, подобную проблему. На данный момент я пошел с решением ниже, которое по существу представляет собой реализацию ответа TREE (обновленный) с использованием общего абстрактного базового класса, чтобы избежать дублирования всякий раз, когда вам нужен этот механизм.

Конкретные тесты предоставили бы метод @Parameters, который возвращает итерабельность одноэлементных массивов, содержащих Поставщик <T> каждый. Затем эти поставщики выполняются ровно один раз на фактический ввод, необходимый для конкретных методов тестирования.

@RunWith(Parameterized.class)
public class AbstractBufferedInputTest<T> {

private static Object INPUT_BUFFER;

private static Object PROVIDER_OF_BUFFERED_INPUT;

private T currentInput;

@SuppressWarnings("unchecked")
public AbstractBufferedInputTest(Supplier<T> inputSuppler) {
    if (PROVIDER_OF_BUFFERED_INPUT != inputSuppler) {
        INPUT_BUFFER = inputSuppler.get();
        PROVIDER_OF_BUFFERED_INPUT = inputSuppler;
    }
    currentInput = (T) INPUT_BUFFER;
}

/**
 * 
 * @return the input to be used by test methods
 */
public T getCurrentInput() {
    return currentInput;
}

}

Ответ 5

Вы можете выполнить инициализацию в методе @Before, записывая переменную экземпляра, но проверяя значение null.

@RunWith(value = Parameterized.class)
public class BigThingTests {
  private BigThing bigThing;

  @Before
  public void createBitThing() {
    if (bigThing == null) {
      bigThing = new BigThing();
    }
  }

...
}

Для каждого набора параметров создается новый экземпляр BigThingTests, а bigThing устанавливается с нулевым значением с каждым новым экземпляром. Бегун Parameterized является однопоточным, поэтому вам не нужно беспокоиться о нескольких инициализациях.