有几个接口允许您修改 TestNG 的行为。这些接口被广泛地称为“TestNG Listeners”。以下是一些监听器:

当您实现其中一个接口时,您可以通过以下任一方式让 TestNG 知道它:

使用testng.xml或 Java指定监听器

以下是在testng.xml文件中定义侦听器的方法:

  1. <suite>
  2. <listeners>
  3. <listener class-name="com.example.MyListener" />
  4. <listener class-name="com.example.MyMethodInterceptor" />
  5. </listeners>
  6. ...

或者,如果您更喜欢在 Java 中定义这些侦听器:

  1. @Listeners({ com.example.MyListener.class, com.example.MyMethodInterceptor.class })
  2. public class MyTest {
  3. // ...
  4. }

该@Listeners注释可以包含任何扩展类org.testng.ITestNGListener 除了 IAnnotationTransformer和IAnnotationTransformer2。原因是这些侦听器需要在流程的早期就知道,以便 TestNG 可以使用它们来重写您的注解,因此您需要在testng.xml文件中指定这些侦听器。
请注意,@Listeners注解将应用于您的整个套件文件,就像您在testng.xml文件中指定它一样。如果你想限制它的范围(例如,只在当前类上运行),你的监听器中的代码可以首先检查即将运行的测试方法并决定接下来要做什么。这是如何做到:
首先定义一个新的自定义注解,可以用来指定这个限制:

  1. @Retention(RetentionPolicy.RUNTIME)
  2. @Target ({ElementType.TYPE})
  3. public @interface DisableListener {}

在您的常规监听器Listener中添加如下编辑检查:

  1. public void beforeInvocation(IInvokedMethod iInvokedMethod, ITestResult iTestResult) {
  2. ConstructorOrMethod consOrMethod =iInvokedMethod.getTestMethod().getConstructorOrMethod();
  3. DisableListener disable = consOrMethod.getMethod().getDeclaringClass().getAnnotation(DisableListener.class);
  4. if (disable != null) {
  5. return;
  6. }
  7. // else resume your normal operations
  8. }

注解不调用侦听器的测试类:

  1. @DisableListener
  2. @Listeners({ com.example.MyListener.class, com.example.MyMethodInterceptor.class })
  3. public class MyTest {
  4. // ...
  5. }

使用ServiceLoader指定侦听器

JDK 提供了一种非常优雅的机制来通过ServiceLoader类在类路径上指定接口的实现。
使用 ServiceLoader,您需要做的就是创建一个 jar 文件,其中包含您的侦听器和一些配置文件,当您运行 TestNG 时将该 jar 文件放在类路径中,TestNG 会自动找到它们。
它如何工作的具体示例:
创建一个监听器

  1. package test.tmp;
  2. public class TmpSuiteListener implements ISuiteListener {
  3. @Override
  4. public void onFinish(ISuite suite) {
  5. System.out.println("Finishing");
  6. }
  7. @Override
  8. public void onStart(ISuite suite) {
  9. System.out.println("Starting");
  10. }
  11. }

编译此文件,然后在META-INF/services/org.testng.ITestNGListener位置创建一个文件,该文件将命名此接口所需的实现。
最终应该得到以下目录结构,其中只有两个文件:

  1. $ tree
  2. |____META-INF
  3. | |____services
  4. | | |____org.testng.ITestNGListener
  5. |____test
  6. | |____tmp
  7. | | |____TmpSuiteListener.class
  8. $ cat META-INF/services/org.testng.ITestNGListener
  9. test.tmp.TmpSuiteListener

创建此目录的 jar:

  1. $ jar cvf ../sl.jar .
  2. added manifest
  3. ignoring entry META-INF/
  4. adding: META-INF/services/(in = 0) (out= 0)(stored 0%)
  5. adding: META-INF/services/org.testng.ITestNGListener(in = 26) (out= 28)(deflated -7%)
  6. adding: test/(in = 0) (out= 0)(stored 0%)
  7. adding: test/tmp/(in = 0) (out= 0)(stored 0%)
  8. adding: test/tmp/TmpSuiteListener.class(in = 849) (out= 470)(deflated 44%)

接下来,在调用 TestNG 时将此 jar 文件放在类路径中:

  1. $ java -classpath sl.jar:testng.jar org.testng.TestNG testng-single.yaml
  2. Starting
  3. f2 11 2
  4. PASSED: f2("2")
  5. Finishing

这种机制允许您将相同的侦听器集应用于整个组织,只需将 jar 文件添加到类路径,而不是要求每个开发人员记住在他们的 testng.xml 文件中指定这些侦听器。