TestNG测试结果报告

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注释中的 dependsOnGroupsdependsOnMethods使用户能够定义测试方法之间的依赖关系。这种依赖关系也就决定这些测试方法必须按着怎样的顺序运行

第二类
除了第一类有依赖关系的剩下的全部归于第二类,尽管默认 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>
image.png

监听器的使用方法

在 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又不能够提供这些信息的时候非常有用。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容