TestNG监听器

TestNG的几种监听器

TestNG提供了一些接口,实现了在测试的不同时期内进行一些操作,主要有ITestListener、ISuiteListener、IInvokedMethodListener2、IExecutionListener、ITestListener等,所有listener接口都是继承自ITestNGListener接口。使用监听器的时候,需要自己新建一个类,实现相应的接口,并实现每个接口中的抽象方法,下面先演示如何用监听器。

创建监听器类

下面的代码新建了一个MyListener类,implements ITestListener接口。需要实现ITestListener接口中的7个方法。他们传进来的参数有2种:ITestResult和ITestContext,后面再介绍他们。其他的监听器都是这样使用的,只不过需要实现的方法是不同的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.test.listener;

import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;

public class MyListener implements ITestListener{

@Override
public void onTestStart(ITestResult result) {
System.out.println("ITestListener_onTestStart:");
}

@Override
public void onTestSuccess(ITestResult result) {
System.out.println("ITestListener_onTestSuccess:");
}

@Override
public void onTestFailure(ITestResult result) {
System.out.println("ITestListener_onTestFailure:");
}

@Override
public void onTestSkipped(ITestResult result) {
System.out.println("ITestListener_onTestSkipped:");
}

@Override
public void onTestFailedButWithinSuccessPercentage(ITestResult result) { }

@Override
public void onStart(ITestContext context) {
System.out.println("ITestListener_onStart:");
}

@Override
public void onFinish(ITestContext context) {
System.out.println("ITestListener_onFinish:");
}
}

不同监听器中的方法

  1. ITestListener:onTestStart、onTestSuccess、onTestSuccess、onTestFailure、onTestSkipped、onTestFailedButWithinSuccessPercentage、onStart、onFinish
  2. IExecutionListener:onExecutionStart、onExecutionFinish
  3. IInvokedMethodListener2:beforeInvocation、afterInvocation、beforeInvocation、afterInvocation
  4. ISuiteListener:onStart、onFinish
  5. IConfigurationListener2:onConfigurationSuccess、onConfigurationFailure、onConfigurationSkip、beforeConfiguration

ITestListener和ISuiteListener的方法都比较好理解,我们来看一下他们格子的执行时机。假设有一个测试基类和测试类,他们各自都有@BeforeTest、@AfterTest、@BeforeClass、@AfterClass、@BeforeSuite和@AfterSuite方法。从打印的顺序中看一下他们执行的顺序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
[RemoteTestNG] detected TestNG version 6.8.9
IExecutionListener_onExecutionStart
ISuiteListener_onStart
IConfigurationListener2_beforeConfiguration
IInvokedMethodListener2_beforeInvocation
测试类的@BeforeSuite
IInvokedMethodListener2_afterInvocation
IConfigurationListener2_onConfigurationSuccess
ITestListener_onStart:
IConfigurationListener2_beforeConfiguration
IInvokedMethodListener2_beforeInvocation
基类的@BeforeTest
IInvokedMethodListener2_afterInvocation
IConfigurationListener2_onConfigurationSuccess
IConfigurationListener2_beforeConfiguration
IInvokedMethodListener2_beforeInvocation
测试类的@BeforeClass
IInvokedMethodListener2_afterInvocation
IConfigurationListener2_onConfigurationSuccess
IConfigurationListener2_beforeConfiguration
IInvokedMethodListener2_beforeInvocation
测试类的@BeforeTest
IInvokedMethodListener2_afterInvocation
IConfigurationListener2_onConfigurationSuccess
测试类的@DataProvider
ITestListener_onTestStart:
IInvokedMethodListener2_beforeInvocation
测试类的@Test
IInvokedMethodListener2_afterInvocation
ITestListener_onTestSuccess:
ITestListener_onTestStart:
IInvokedMethodListener2_beforeInvocation
测试类的@Test
IInvokedMethodListener2_afterInvocation
ITestListener_onTestSuccess:
IConfigurationListener2_beforeConfiguration
IInvokedMethodListener2_beforeInvocation
测试类的@AfterClass
IInvokedMethodListener2_afterInvocation
IConfigurationListener2_onConfigurationSuccess
IConfigurationListener2_beforeConfiguration
IInvokedMethodListener2_beforeInvocation
测试类的@AfterTest
IInvokedMethodListener2_afterInvocation
IConfigurationListener2_onConfigurationSuccess
IConfigurationListener2_beforeConfiguration
IInvokedMethodListener2_beforeInvocation
基类的@AfterTest
IInvokedMethodListener2_afterInvocation
IConfigurationListener2_onConfigurationSuccess
ITestListener_onFinish:
IConfigurationListener2_beforeConfiguration
IInvokedMethodListener2_beforeInvocation
测试类的@AfterSuite
IInvokedMethodListener2_afterInvocation
IConfigurationListener2_onConfigurationSuccess
ISuiteListener_onFinish

===============================================
TestAllSheets
Total tests run: 2, Failures: 0, Skips: 0
===============================================

IExecutionListener_onExecutionFinish

监听器的使用

一种方法是在具体的测试方法前加上@Listeners注释,注释的括号里指明用哪个listener类,例如:

1
2
3
4
5
6
7
@Listeners(MyListener.class)
public class listenerTest {
@Test
public void templistener1(){
System.out.println("i'm listenerTest1");
}
}

第二种是在testng.xml文件中为测试套件制定listener,可以一个也可以多个,具体方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="TestAllSheets">
<listeners>
<listener class-name="com.test.listener.MyListener"></listener>
<listener class-name="com.test.listener.MyForthListener"></listener>
<listener class-name="com.test.listener.MyFifthListener"></listener>
<listener class-name="com.test.listener.MySecondListener"></listener>
<listener class-name="com.test.listener.MyThirdListener"></listener>
</listeners>
<test name="TestAllSheets" preserve-order="true">
<classes>
<class name="com.test.mutipulapi.TestAllSheets"></class>
</classes>
</test>
</suite>

监听器接口方法中传入的参数

比如ITestListener接口中onTestStart方法会传进来一个ITestResult类型的参数,其他的还有ITestContext、IInvokedMethod等,来看看可以用他们做什么吧。

ITestResult类

先上源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package org.testng;

/**
* This class describes the result of a test.
*
* @author Cedric Beust, May 2, 2004
* @since May 2, 2004
* @version $Revision: 721 $, $Date: 2009-05-23 09:55:46 -0700 (Sat, 23 May 2009) $
*
*/
public interface ITestResult extends IAttributes, Comparable<ITestResult> {

//
// Test status
//
public static final int SUCCESS = 1;
public static final int FAILURE = 2;
public static final int SKIP = 3;
public static final int SUCCESS_PERCENTAGE_FAILURE = 4;
public static final int STARTED= 16;

/**
* @return The status of this result, using one of the constants
* above.
*/
public int getStatus();
public void setStatus(int status);

/**
* @return The test method this result represents.
*/
public ITestNGMethod getMethod();

/**
* @return The parameters this method was invoked with.
*/
public Object[] getParameters();
public void setParameters(Object[] parameters);

/**
* @return The test class used this object is a result for.
*/
public IClass getTestClass();

/**
* @return The throwable that was thrown while running the
* method, or null if no exception was thrown.
*/
public Throwable getThrowable();
public void setThrowable(Throwable throwable);

/**
* @return the start date for this test, in milliseconds.
*/
public long getStartMillis();

/**
* @return the end date for this test, in milliseconds.
*/
public long getEndMillis();
public void setEndMillis(long millis);

/**
* @return The name of this TestResult, typically identical to the name
* of the method.
*/
public String getName();

/**
* @return true if if this test run is a SUCCESS
*/
public boolean isSuccess();

/**
* @return The host where this suite was run, or null if it was run locally. The
* returned string has the form: host:port
*/
public String getHost();

/**
* The instance on which this method was run.
*/
public Object getInstance();

/**
* If this result's related instance implements ITest, returns its test name, otherwise returns null.
*/
public String getTestName();

public String getInstanceName();

/**
* @return the {@link ITestContext} for this test result.
*/
public ITestContext getTestContext();
}

来试一下这些方法调用以后得到的值是什么,假设我在自己实现的ITestListener类中,onTestSuccess方法里用传入的result示例来打印一些信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Override
public void onTestSuccess(ITestResult result) {
System.out.println("ITestListener_onTestSuccess:");
System.out.println("result status:" + result.getStatus());
System.out.println("result host:" + result.getHost());
System.out.println("result instance name:" + result.getInstanceName());
System.out.println("result name:" + result.getName());
System.out.println("result start millis:" + result.getStartMillis());
System.out.println("result end millis:" + result.getEndMillis());
System.out.println("result name:" + result.getName());
System.out.println("result test name:" + result.getTestName());
System.out.println("result is success:" + result.isSuccess());

ITestNGMethod method = result.getMethod();
System.out.println("result method description:" + method.getDescription());

Object[] parameters = result.getParameters();
System.out.println("result parameters:" + parameters.getClass().getSimpleName());
}

下面是打印的结果

1
2
3
4
5
6
7
8
9
10
11
12
ITestListener_onTestSuccess:
result status:1
result host:null
result instance name:com.test.mutipulapi.TestAllSheets
result name:testDifferentSheets
result start millis:1566893197588
result end millis:1566893201413
result name:testDifferentSheets
result test name:null
result is success:true
result method description:null
result parameters:Object[]

ITestContext类

源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package org.testng;

import com.google.inject.Injector;
import com.google.inject.Module;

import org.testng.xml.XmlTest;

import java.util.Collection;
import java.util.Date;
import java.util.List;


/**
* This class defines a test context which contains all the information
* for a given test run. An instance of this context is passed to the
* test listeners so they can query information about their
* environment.
*
* @author Cedric Beust, Aug 6, 2004
* @author <a href='mailto:the_mindstorm@evolva.ro'>Alexandru Popescu</a>
*/
public interface ITestContext extends IAttributes {

/**
* The name of this test.
*/
public String getName();

/**
* When this test started running.
*/
public Date getStartDate();

/**
* When this test stopped running.
*/
public Date getEndDate();

/**
* @return A list of all the tests that run successfully.
*/
public IResultMap getPassedTests();

/**
* @return A list of all the tests that were skipped
*/
public IResultMap getSkippedTests();

/**
* @return A list of all the tests that failed but are being ignored because
* annotated with a successPercentage.
*/
public IResultMap getFailedButWithinSuccessPercentageTests();

/**
* @return A map of all the tests that passed, indexed by
* their ITextMethor.
*
* @see org.testng.ITestNGMethod
*/
public IResultMap getFailedTests();

/**
* @return All the groups that are included for this test run.
*/
public String[] getIncludedGroups();

/**
* @return All the groups that are excluded for this test run.
*/
public String[] getExcludedGroups();

/**
* @return Where the reports will be generated.
*/
public String getOutputDirectory();

/**
* @return The Suite object that was passed to the runner
* at start-up.
*/
public ISuite getSuite();

/**
* @return All the test methods that were run.
*/
public ITestNGMethod[] getAllTestMethods();

/**
* @return The host where this test was run, or null if it was run locally. The
* returned string has the form: host:port
*/
public String getHost();

/**
* @return All the methods that were not included in this test run.
*/
public Collection<ITestNGMethod> getExcludedMethods();

/**
* Retrieves information about the successful configuration method invocations.
*/
public IResultMap getPassedConfigurations();

/**
* Retrieves information about the skipped configuration method invocations.
*/
public IResultMap getSkippedConfigurations();

/**
* Retrieves information about the failed configuration method invocations.
*/
public IResultMap getFailedConfigurations();

/**
* @return the current XmlTest.
*/
public XmlTest getCurrentXmlTest();

public List<Module> getGuiceModules(Class<? extends Module> cls);
public void addGuiceModule(Class<? extends Module> cls, Module module);

public Injector getInjector(List<Module> moduleInstances);
public void addInjector(List<Module> moduleInstances, Injector injector);
}

在他的onFinish方法中尝试打印一些信息:

1
2
3
4
5
6
7
8
@Override
public void onFinish(ITestContext context) {
System.out.println("ITestListener_onFinish:");
System.out.println("context name:" + context.getName());
System.out.println("context suite name:" + context.getSuite().getName());
System.out.println("context start date:" + context.getStartDate().toString());
System.out.println("context end date:" + context.getEndDate().toString());
}

打印结果:

1
2
3
4
context name:TestAllSheets
context suite name:TestAllSheets
context start date:Tue Aug 27 16:10:16 CST 2019
context end date:Tue Aug 27 16:10:31 CST 2019

IInvokedMethod类

这个类中提供了5个方法,都很简单,就不详细写了,五个方法的解释如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package org.testng;

/**
* An interface representing a method that has been invoked by TestNG.
*
* This interface is internal.
*/
public interface IInvokedMethod {

/**
* @return true if this method is a test method
*/
public abstract boolean isTestMethod();

/**
* @return true if this method is a configuration method (@BeforeXXX or @AfterXXX)
*/
public abstract boolean isConfigurationMethod();

/**
* @return the test method
*/
public abstract ITestNGMethod getTestMethod();

public ITestResult getTestResult();

/**
* @return the date when this method was run
*/
public abstract long getDate();

}

总结

监听器顾名思义就是帮助使用者从程序的不同环节中获取他需要的数据,TestNG的监听器使用起来比较简单,本身他的报告中提供的信息就不少,对于需要更加详细的数据的,就可以借助监听器,来丰富报告的数据。