Я пишу некоторые тесты 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-интерфейс фреймворка?