Вы можете создать собственное расширение AfterEachCallback
и применить его к необходимым методам тестирования. Это расширение будет выполняться после каждого теста, к которому оно применено. Затем, используя пользовательские аннотации, вы можете связать определенные методы очистки с конкретными тестами. Вот пример расширения:
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.List;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
import org.junit.jupiter.api.extension.ExtensionContext.Store;
import org.junit.platform.commons.support.AnnotationSupport;
import org.junit.platform.commons.support.HierarchyTraversalMode;
public class CleanupExtension implements AfterEachCallback {
private static final Namespace NAMESPACE = Namespace.create(CleanupExtension.class);
private static boolean namesMatch(Method method, String name) {
return method.getAnnotation(CleanMethod.class).value().equals(name);
}
private static Exception suppressOrReturn(final Exception previouslyThrown,
final Exception newlyThrown) {
if (previouslyThrown == null) {
return newlyThrown;
}
previouslyThrown.addSuppressed(newlyThrown);
return previouslyThrown;
}
@Override
public void afterEach(final ExtensionContext context) throws Exception {
final Method testMethod = context.getRequiredTestMethod();
final Cleanup cleanupAnno = testMethod.getAnnotation(Cleanup.class);
final String cleanupName = cleanupAnno == null ? "" : cleanupAnno.value();
final List<Method> cleanMethods = getAnnotatedMethods(context);
final Object testInstance = context.getRequiredTestInstance();
Exception exception = null;
for (final Method method : cleanMethods) {
if (namesMatch(method, cleanupName)) {
try {
method.invoke(testInstance);
} catch (Exception ex) {
exception = suppressOrReturn(exception, ex);
}
}
}
if (exception != null) {
throw exception;
}
}
@SuppressWarnings("unchecked")
private List<Method> getAnnotatedMethods(final ExtensionContext methodContext) {
// Use parent (Class) context so methods are cached between tests if needed
final Store store = methodContext.getParent().orElseThrow().getStore(NAMESPACE);
return store.getOrComputeIfAbsent(
methodContext.getRequiredTestClass(),
this::findAnnotatedMethods,
List.class
);
}
private List<Method> findAnnotatedMethods(final Class<?> testClass) {
final List<Method> cleanMethods = AnnotationSupport.findAnnotatedMethods(testClass,
CleanMethod.class, HierarchyTraversalMode.TOP_DOWN);
for (final Method method : cleanMethods) {
if (method.getParameterCount() != 0) {
throw new IllegalStateException("Methods annotated with "
+ CleanMethod.class.getName() + " must not have parameters: "
+ method
);
}
}
return cleanMethods;
}
@ExtendWith(CleanupExtension.class)
@Retention(RUNTIME)
@Target(METHOD)
public @interface Cleanup {
String value() default "";
}
@Retention(RUNTIME)
@Target(METHOD)
public @interface CleanMethod {
String value() default "";
}
}
И тогда ваш тестовый класс может выглядеть так:
import org.junit.jupiter.api.Test;
class Tests {
@Test
@CleanupExtension.Cleanup
void testWithExtension() {
System.out.println("#testWithExtension()");
}
@Test
void testWithoutExtension() {
System.out.println("#testWithoutExtension()");
}
@Test
@CleanupExtension.Cleanup("alternate")
void testWithExtension_2() {
System.out.println("#testWithExtension_2()");
}
@CleanupExtension.CleanMethod
void performCleanup() {
System.out.println("#performCleanup()");
}
@CleanupExtension.CleanMethod("alternate")
void performCleanup_2() {
System.out.println("#performCleanup_2()");
}
}
Запуск Tests
Я получаю следующий вывод:
#testWithExtension()
#performCleanup()
#testWithExtension_2()
#performCleanup_2()
#testWithoutExtension()
Это расширение будет применяться к любому методу тестирования, помеченному CleanupExtension.Cleanup
или ExtendWith(CleanupExtension.class)
. Цель первой аннотации - объединить конфигурацию с аннотацией, которая также применяет расширение. Затем после каждого метода тестирования расширение будет вызывать любые методы в иерархии классов, помеченные CleanupExtension.CleanMethod
. И Cleanup
, и CleanMethod
имеют атрибут String
. Этот атрибут является «именем», и только CleanMethod
s, которые имеют «имя», совпадающее с тестом Cleanup
, будут выполнены. Это позволяет связать определенные методы тестирования с конкретными методами очистки.
Для получения дополнительной информации о расширениях JUnit Jupiter см. §5 Руководства пользователя . Также для CleanupExtension.Cleanup
я использую функцию мета-аннотации / составной аннотации, описанную в §3.1.1 .
Обратите внимание, что это сложнее, чем ответ , заданный @ Roman Konoval , но он может быть более удобным, если вам придется делать подобные вещи много раз. Однако, если вам нужно сделать это только для одного или двух тестовых занятий, я рекомендую ответ Романа.