Как предоставить параметр для метода @BeforeEach на каждом @Test - PullRequest
0 голосов
/ 28 августа 2018

Я пишу некоторые тесты JUnit с помощью JUnit 5. Перед каждым тестом мне нужно загрузить тестовый ресурс и инициализировать с ним некоторые другие вещи. Для этого я написал свой метод init, помеченный @BeforeEach, потому что этот прогресс всегда один и тот же, за исключением того, что ресурс для загрузки должен быть разным для каждого теста.
Сначала я подумал об удалении аннотации @BeforeEach, добавил параметр в метод init, чтобы указать, какой ресурс должен быть загружен, и сам вызывал метод init из каждого теста в начале.

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

public class MyTest {
   private Object testResource;

   private void init(String resourcePath) {
      // actually load the resource and initialize some fields here
      this.testResource = "Loaded resource from: " + resourcePath;
   }

   @Test
   public void test0() {
      init("TestResource0");
      assertEquals("Loaded resource from: TestResource0", testResource);
   }

   @Test
   public void test1() {
      init("TestResource1");
      assertEquals("Loaded resource from: TestResource1", testResource);
   }

}

Таким образом, я чувствую, что подрываю всю структуру потока тестов JUnit, и боюсь, что это может вызвать некоторые проблемы в будущем при расширении тестов, например, какое-то необычное программирование мета-теста, где я буду полагаться на JUnit для предоставления правильной информации о текущем состоянии теста.
Поэтому я решил оставить параметр ресурса для загрузки в методе init и оставить аннотацию @BeforeEach. Таким образом, мне нужно было включить ParameterResolver. Моя первая мысль о реализации resolveParameter(ParameterContext, ExtensionContext) состояла в том, чтобы сначала выяснить, какой тест должен быть выполнен, и вернуть соответствующий ресурс, который будет загружен для этого теста.

static class MyParamResolver implements ParameterResolver {

      @Override
      public Object resolveParameter(ParameterContext parameterContext,
                                     ExtensionContext extensionContext) throws ParameterResolutionException {

         String test = extensionContext.getRequiredTestMethod()
                                       .getName();

         switch (test) {
         case "test0":
            return "TestResource0";
         case "test1":
            return "TestResource1";
         }

         throw new ParameterResolutionException("Unknown test " + test);
      }

      @Override
      public boolean supportsParameter(ParameterContext parameterContext,
                                       ExtensionContext extensionContext) {
         return true;
      }

   }

Мне не нравится это решение, потому что у меня, во-первых, нет безопасности для правильности имен, обеспечиваемых компилятором, и, во-вторых, загружаемые ресурсы явно не связаны с соответствующим тестом с первого взгляда. Затем я подумал, что было бы неплохо как-то указать путь ресурса к аннотации, которая напрямую связана с методом тестирования. Примерно так:

@Test("test0")
public void test0() {
    assertEquals("Loaded resource from: TestResource0", testResource);
}

@Test("test1")
public void test1() {
   assertEquals("Loaded resource from: TestResource1", testResource);
}

...

    @Override
    public Object resolveParameter(ParameterContext parameterContext,
                                   ExtensionContext extensionContext) {

        return extensionContext.getRequiredTestMethod()
                               .getAnnotation(Test.class)
                               .value();
     }

К сожалению, аннотация @Test не определяет какие-либо параметры, и после некоторых исследований в документах JUnit я не смог найти здесь какую-либо другую аннотацию. Лучшее, что я могу придумать сейчас, - это создать собственную аннотацию и поместить ее в каждый метод тестирования. Но я также считаю, что это общая проблема, которую можно решить, не изобретая саму себя заново. Я просто не мог ничего найти.
Есть ли удобный способ решения этой проблемы, при котором не нужно придумывать собственные аннотации. Другими словами: есть ли простой способ, который поддерживает качество кода и удобочитаемость, чтобы решить эту проблему, просто используя уже созданный API-интерфейс фреймворка?

Ответы [ 2 ]

0 голосов
/ 28 августа 2018

ParameterizedTest полезно, когда у вас есть те же самые шаги для теста, но вы хотите выполнить его с другими параметрами. Кажется, это не так. Вы можете просто использовать параметр TestInfo для метода @BeforeEach для обработки вашего дела.

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;

public class JUnitTest {

    @Test public void test1() {
        System.out.println("Test");
    }

    @BeforeEach public void f(TestInfo info) {
        System.out.println(info.getDisplayName());
    }
}
0 голосов
/ 28 августа 2018

Полагаю, вы ищете "шаблоны контейнеров". Они еще не являются частью Юпитера. Но уже запланировано на 5,4: https://github.com/junit-team/junit5/issues/871

...