Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何仅在标记测试之后运行清理方法?_Java_Junit_Junit5 - Fatal编程技术网

Java 如何仅在标记测试之后运行清理方法?

Java 如何仅在标记测试之后运行清理方法?,java,junit,junit5,Java,Junit,Junit5,我正在为我的Java项目编写JUnit5测试 我有一些测试方法需要花费时间清理(在每次清理之后)。理想情况下,我希望用一些注释标记它们,并只为它们运行清理方法 这就是我所尝试的: class MyTest { @AfterEach @Tag("needs-cleanup") void cleanup() { //do some complex stuff } @Test void test1() { //do

我正在为我的Java项目编写JUnit5测试

我有一些测试方法需要花费时间清理(在每次清理之后)。理想情况下,我希望用一些注释标记它们,并只为它们运行清理方法

这就是我所尝试的:

class MyTest {

    @AfterEach
    @Tag("needs-cleanup")
    void cleanup() {
        //do some complex stuff
    }

    @Test
    void test1() {
         //do test1
    }

    @Test
    @Tag("needs-cleanup")
    void test2() {
         //do test2
    }
}
我希望
cleanup
方法仅在
test2
之后运行。但它实际上是在两次测试之后运行的

是否可以通过JUnit5注释的某种组合来实现它?我不想将我的测试类拆分为几个类,也不想直接从测试方法调用
cleanup

您可以向测试中注入并检查测试的注释标签:

class MyTest {
  private TestInfo testInfo;

  MyTest(TestInfo testInfo) {
    this.testInfo = testInfo;
  }

  @AfterEach
  void cleanup() {
    if (this.testInfo.getTags().contains("needs-cleanup")) {
        // .. do cleanup
    } 
  }

  @Test
  void test1() {
     //do test1
  }

  @Test
  @Tag("needs-cleanup")
  void test2() {
     //do test2
  }

}
您可以创建自己的扩展并将其应用于所需的测试方法。此扩展将在应用于的每个测试之后执行。然后,使用自定义注释,可以将特定清理方法与特定测试链接起来。下面是扩展的一个示例:

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 "";

  }

}
运行
测试
会得到以下输出:

#testWithExtension()
#性能清理()
#扩展名为_2()的测试
#性能清理_2()
#testWithoutExtension()
此扩展将应用于任何带有
CleanupExtension.Cleanup
extendedwith(CleanupExtension.class)
注释的测试方法。前一个注释的目的是将配置与同样应用扩展的注释相结合。然后,在每个测试方法之后,扩展将调用类层次结构中用
CleanupExtension.CleanMethod
注释的任何方法。
Cleanup
CleanMethod
都具有
String
属性。此属性是“名称”,仅执行与
Cleanup
测试具有匹配“名称”的
CleanMethod
s。这允许您将特定的测试方法链接到特定的清理方法


有关JUnit Jupiter扩展的更多信息,请参阅。另外,对于
CleanupExtension.Cleanup
我正在使用中描述的元注释/复合注释功能

请注意,这比@Roman Konova给出的更复杂,但如果您必须多次执行此类操作,则可能更方便用户。但是,如果您只需要对一个或两个测试类执行此操作,我建议您使用Roman的答案。

来自文档:

TestInfo:如果方法参数的类型为TestInfo,则 TestInfo参数Resolver将提供TestInfo的一个实例 对应于当前测试作为参数值。这个 然后,可以使用TestInfo检索有关当前数据库的信息 测试,例如测试的显示名称、测试类、测试方法、, 或相关标签。显示名称可以是技术名称,例如 作为测试类或测试方法的名称,或自定义名称 通过@DisplayName配置

TestInfo充当中TestName规则的插入式替换 少年4

关于上述描述,您可以使用TestInfo类,该类为您提供了应该为其运行清理的类的信息,然后您需要检查条件,并通过检查它们的标记来允许它们:

@AfterEach 
void afterEach(TestInfo info) {
    if(!info.getTags().contains("cleanItUp")) return; // preconditioning only to needs clean up
        //// Clean up logic Here
}


@Test
@Tag("cleanItUp")
void myTest() {

}

是否应在每次特殊试验后或所有特殊试验后进行清理?每次特殊试验后进行清洗
@AfterEach 
void afterEach(TestInfo info) {
    if(!info.getTags().contains("cleanItUp")) return; // preconditioning only to needs clean up
        //// Clean up logic Here
}


@Test
@Tag("cleanItUp")
void myTest() {

}