TestNG默认情况下,会生产两种类型的测试报告HTML的和XML的。 测试报告位于 "test-output" 目录下。
TestNG的还允许用户自己写的报告,并用它使用TestNG。还有一个选项来写你自己的记录器,在运行时通过TestNG的通知
监听器: 为了实现一个监听类,实现一个 ITestListener接口或者其它接口。这些类在运行时通知了TestNG测试开始时,结束后,失败,跳过或传递。
记录器: 为了实现一个报表类,实现一个org.testng.IReporter接口。这些类一整套运行结束时调用。调用时,该对象包含整个测试运行的信息传递到这个类。
IAnnotationTransformer
IAnnotationTransformer 监听器只能用来修改 @Test 注释
IAnnotationTransformer 要求实现 transform 方法,其方法签名如下:
void transform(ITest annotation, Class testClass, Constructor testConstructor, Method testMethod);
annotation 代表就是为 testMethod 定义的 @Test 注释
调用其方法可以更改 @Test 注释属性
例如,下面的代码在运行时将属性 enabled 改为 false 从而禁用了当前的测试方法
annotation.setEnabled(false);
IAnnotationTransformer2
IAnnotationTransformer2 监听器修改其他 TestNG 的注释(比如,@DataProvider, @Factory )
该监听器要求实现的方法:
void transform(IConfigurationAnnotation annotation, java.lang.Class testClass,
java.lang.reflect.Constructor testConstructor,
java.lang.reflect.Method testMethod)
void transform(IDataProviderAnnotation annotation, java.lang.reflect.Method method)
void transform(IFactoryAnnotation annotation, java.lang.reflect.Method method)
IHookable
IHookable 监听器提供了类似与面向q切面编程(AOP)中的 Around Advice 的功能
它在测试方法执行前后提供了切入点,从而使用户在测试方法运行前后注入特定的功能
例如: 用户可以在当前测试方法运行前加入特定的验证逻辑以决定测试方法是否运行或者跳过,甚至覆盖测试方法的逻辑
IHookable 监听器要求实现的方法签名
void run(IHookCallBack callBack, ITestResult testResult)
运行原始测试方法逻辑,需要调用 runTestMethod 方法
callBack.runTestMethod(testResult);
用JAAS(Java验证和授权API)一个例子:
public class MyHook implements IHookable {
public void run(final IHookCallBack icb, ITestResult testResult) {
// Preferably initialized in a @Configuration method
mySubject = authenticateWithJAAs();
Subject.doAs(mySubject, new PrivilegedExceptionAction() {
public Object run() {
icb.callback(testResult);
}
};
}
}
IInvokedMethodListener
与 IHookable 类似,IInvokedMethodListener 提供了类似与面向方面编程(AOP)中的 Before Advice 和 After Advice 的功能
IInvokedMethodListener监听器允许用户在当前测试方法被执行前和执行后注入特定的逻辑
比如: 可以加入日志方法,无论何时TestNG即将调用一个测试(被@Test注解的)或者配置(任何使用@Beforeor@After注解标注的方法),监听器 IInvokedMethodListener都可以让你得到通知
public interface IInvokedMethodListener extends ITestNGListener {
void beforeInvocation(IInvokedMethod method, ITestResult testResult);
void afterInvocation(IInvokedMethod method, ITestResult testResult);
}
IMethodInterceptor
TestNG 启动之后,第一件要做的事情是将所有的测试方法分成两类:
一类是顺序运行的测试方法;
一类是没有特定运行顺序的测试方法
第一类
TestNG 通过 @Test
注释中的 dependsOnGroups
和 dependsOnMethods
使用户能够定义测试方法之间的依赖关系。这种依赖关系也就决定这些测试方法必须按着怎样的顺序运行
第二类
除了第一类有依赖关系的剩下的全部归于第二类,尽管默认 TestNG 会尝试用类名将它们分组,但是理论上,它们的运行顺序是随机的,甚至每次运行的顺序都可能不同
IMethodInterceptor 监听器使用户拥有对第二类测试方法更大的控制权
实现的方法:
public interface IMethodInterceptor {
List<IMethodInstance> intercept(List<IMethodInstance> methods, ITestContext context);
}
intercept 方法在所有测试方法被分类后以及所有测试方法被执行前被调用。所有的测试方法将按照 intercept 返回值列表中的顺序被执行。因此,用户在 intercept 方法中可以对列表进行修改,比如重新排序,甚至增加或者减少测试方法。
intercept方法也要返回一个IMethodInstance列表,它可能是下面情况之一:
- 内容与参数中接收的一致,但是顺序不同
- 一组IMethodInstance对象
- 更大的一组IMethodInstance对象
定义了拦截器,就把它传递个TestNG,用下面的方式:
java -classpath "testng-jdk15.jar:test/build" org.testng.TestNG -listener test.methodinterceptors.NullMethodInterceptor
-testclass test.methodinterceptors.FooTest
例如,下面是个方法拦截器会重新给方法排序,一遍“fast”组中的方法总是先执行:
public List<IMethodInstance> intercept(List<IMethodInstance> methods, ITestContext context) {
List<IMethodInstance> result = new ArrayList<IMethodInstance>();
for (IMethodInstance m : methods) {
Test test = m.getMethod().getConstructorOrMethod().getAnnotation(Test.class);
Set<String> groups = new HashSet<String>();
for (String group : test.groups()) {
groups.add(group);
}
if (groups.contains("fast")) {
result.add(0, m);
}
else {
result.add(m);
}
}
return result;
}
ISuiteListener
ISuiteListener 类似于 IInvokedMethodListener,区别是 IInvokedMethodListener 针对的是测试方法,而 ISuiteListener 针对的是测试套件
ISuiteListener 监听器使用户有机会在测试套件开始执行以及执行结束之后嵌入自己的逻辑。
实现的方法 :
void onFinish(ISuite suite)
void onStart(ISuite suite)
ITestListener
ITestListener 监听器要求实现的方法中包含如下三个
void onTestFailure(ITestResult result)
void onTestSkipped(ITestResult result)
void onTestSuccess(ITestResult result)
TestListenerAdapter 已经实现 ITestListener,并且提供了一些有用的方法,比如分别获取所有成功失败跳过三种测试结果的测试方法的方法,并且 ITestListner 中有很多方法而 TestListenerAdapter 已给出了默认实现
扩展TestListenerAdapter,它使用空方法实现了ITestListener
对每个传递进来的测试显示"."的监听器,如果测试失败则显示 "F" ,跳过则是"S":
public class DotTestListener extends TestListenerAdapter {
private int m_count = 0;
@Override
public void onTestFailure(ITestResult tr) {
log("F");
}
@Override
public void onTestSkipped(ITestResult tr) {
log("S");
}
@Override
public void onTestSuccess(ITestResult tr) {
log(".");
}
private void log(String string) {
System.out.print(string);
if (++m_count % 40 == 0) {
System.out.println("");
}
}
}
IReporter
TestNG 提供了默认的测试报表
IReporter 监听器接口只有一个方法:
public void generateReport(List<ISuite> suites, String outputDirectory)
该方法在所有测试方法执行结束后被调用,outputDirectory
是默认的测试报表生成路径,当然可以指定其他路径生成报表
JUnitReport
TestNG 包含了一个可以让TestNG的结果和输出的XML能够被JUnitReport所使用的监听器。
例子: 并且ant任务创建了这个报告:
<target name="reports">
<junitreport todir="test-report">
<fileset dir="test-output">
<include name="*/*.xml"/>
</fileset>
<report format="noframes" todir="test-report"/>
</junitreport>
</target>
监听器的使用方法
在 testng.xml 中使用 TestNG 监听器
TestNG 通过 testng.xml 配置所有的测试方法。
Testng.xml 提供了 listeners 和 listener 标签用来添加自定义的监听器。
<suite name="TestNGSample">
<listeners>
<listener class-name="listeners.OSFilter" />
<listener class-name="listeners.ProgressTracker" />
</listeners>
<test name="ProgressTracker Demo">
<classes>
<class name="tests.SampleTest" />
</classes>
</test>
</suite>
在源代码中使用 TestNG 监听器
通过 @Listeners 注释,可以直接在 Java 源代码中添加 TestNG 监听器。
@Listeners({ OSFilter.class, ProgressTracker.class })
public class SampleTest {
@Test(groups = { OSNames.OS_LINUX })
public void test1() {
sleep(5000);
System.out.println(">>>test1");
}
注意:
在 @Listeners 中添加监听器跟在 testng.xml 添加监听器一样,将被应用到整个测试套件中的测试方法。如果需要控制监听器的应用范围(比如添加的监听器仅使用于某些测试测试类或者某些测试方法),则必须在监听器类中编写适当的判断逻辑。
在 @Listeners 中添加监听器跟在 testng.xml 添加监听器的不同之处在于,它不能添加 IAnnotationTransformer 和 IAnnotationTransformer2 监听器。原因是因为这两种监听器必须在更早的阶段添加到 TestNG 中才能实施修改注释的操作,所以它们只能在 testng.xml 添加。
TestNG 对添加的监听器不做去重判断。因此,如果 testng.xml 和源代码中添加了相同的监听器,该监听器的方法会被调用两次。不要通过多种方式重复添加监听器。
通过 ServiceLoader 使用 TestNG 监听器
JDK中提供了一个非常优雅的机制,通过ServiceLoader类的借口路径来实现监听。
通过 ServiceLoader 的方式使用 TestNG 监听器,简单来说,就是创建一个 jar 文件,里面包含 TestNG 监听器的实现类已经 ServiceLoader 需要的配置信息,并在运行 TestNG 时把该 jar 文件加载到类路径中
这样做的好处是:
- 可以轻松地与其他人分享 TestNG 监听器。
- 当有很多 testng.xml 文件时,不需要重复把监听器添加到每个文件中。
具体例子
先创建一个侦听器(所有的TetstNG监听都应该响应):
package test.tmp;
public class TmpSuiteListener implements ISuiteListener {
@Override
public void onFinish(ISuite suite) {
System.out.println("Finishing");
}
@Override
public void onStart(ISuite suite) {
System.out.println("Starting");
}
}
编译这个文件,然后在当前文件位置创建一个文件META-INF/services/org.testng.ITestNGListener
这个名字就是要实现的接口
目录结构,只有仅仅两个文件:
$ tree
|____META-INF
| |____services
| | |____org.testng.ITestNGListener
|____test
| |____tmp
| | |____TmpSuiteListener.class
在这个目录创建一个jar文件:
jar cvf ../sl.jar .
将jar文件放入调用TestNG的类路径下:
java -classpath sl.jar:testng.jar org.testng.TestNG testng-single.yaml
报表 API
要在HTML报告中显示日志信息,那么就要用到类 org.testng.Reporter:Reporter.log("M3 WAS CALLED");
XML 报表
TestNG 提供一种XML报表器,使得能够捕捉到只适用于TestNG而不适用与JUnit报表的那些特定的信息。
这在用户的测试环境必须要是用TestNG特定信息的XML,而JUnit又不能够提供这些信息的时候非常有用。