内容引入:如何判断测试样例执行完,并查看测试报告?
Java代码执行testNG配置文件
我们先新建一个java project,新建一个类,名为Demo1, 如图所示
package hebu.c.down;
import static org.testng.Assert.assertEquals;
import org.testng.annotations.Test;
public class Demo1 {
@Test
public void test1() {
assertEquals(1,1);
}
@Test
public void test2() {
assertEquals(2,1);
}
}
有一个正确的test,一个失败的。 我们在此类的包上,点击鼠标右键,点击Refresh, 会发现多了一个文件夹:test-output : 这是TestNG在我们执行测试用例失败的时候,自动创建的。 下面新建一个Demo2, 用来只执行失败的test2 , 代码及效果如下: 代码为何这么写,不做过多解释。用就完事了
package hebu.c.down;
import java.util.ArrayList;
import java.util.List;
import org.testng.TestNG;
public class Demo2 {
public static void main(String[] args) throws InterruptedException {
TestNG testNG1 = new TestNG();
List<String> suites1 = new ArrayList<String>();
Thread.sleep(5000);
suites1.add(".\\test-output\\testng-failed.xml");
testNG1.setTestSuites(suites1);
testNG1.run();
}
}
使用ITestContext共享数据
- 可以在类中定义变量,那么类中的所有方法都可以使用。
- 可以使用
ITestContext 共享数据, 它是一个接口,TestNG帮助我们实例化一个对象。 如下图所示
package hebu.c.down;
import static org.testng.Assert.assertEquals;
import org.testng.ITestContext;
import org.testng.annotations.Test;
public class Demo1 {
@Test
public void test1(ITestContext context) {
context.setAttribute("name", "xhx&");
assertEquals(1,1);
}
@Test
public void test2(ITestContext context) {
System.out.println("test2" + "-----" + context.getAttribute("name"));
}
}
ITestResults接口
ITestResult 是TestNG提供的一个接口,结合@AfterMethod ,可以监听@Test方法的执行状态等信息
- 每执行一次测试方法,就会执行一次
@AfterMethod 方法。 ITestResult.getThrowable() 测试的报错信息 ITestResult.getInstanceName()是类名
package hebu.c.down;
import static org.testng.Assert.assertEquals;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;
public class TestResult {
@Test
public void test1(ITestContext context) {
context.setAttribute("name", "xhx&");
assertEquals(1,2);
}
@Test
public void test2() {
assertEquals(1,1);
}
@AfterMethod
public void aMethod(ITestResult result) {
System.out.println("-----aMethod-----");
System.out.println(result.getInstanceName());
if(result.getStatus() == ITestResult.FAILURE) {
System.out.println(result.getInstanceName() + "." + result.getName()+ "--失败了");
}
}
}
结果如下:
监听器
IAnnotationTransformer ,操作@Test
执行的测试方法:
package hebu.c.up;
import org.testng.annotations.Test;
public class DemoforTransform {
@Test
public void test1() {
System.out.println("test1");
}
}
监听作用的类:
package hebu.c.up;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import org.testng.IAnnotationTransformer;
import org.testng.annotations.IAnnotation;
import org.testng.annotations.ITestAnnotation;
public class IAnnotationTransformerDemo implements IAnnotationTransformer{
@Override
public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
annotation.setInvocationCount(5);
}
}
xml文件:(仅是多了<lisreners> 标签)
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd" >
<suite name="Suite1" verbose="1" >
<listeners>
<listener class-name="hebu.c.up.IAnnotationTransformerDemo"></listener>
</listeners>
<test name="Nopackage" >
<classes>
<class name="hebu.c.up.DemoforTransform" />
</classes>
</test>
</suite>
- 与上例重名,与上述的那个不同的是,导入的包不一样。上例导的包为
org.testng.IAnnotationTransformer ,仅用来修改@Test , 而此例中的导入的包为org.testng.internal.annotations.IAnnotationTransformer; , 用来修改除@Test之外的注解,多用于@Factory, 用来替代 IAnnotationTransformer2 , 举一个@Factory的栗子:
先看一下xml的内容:(可以大致知道每个类的大概作用了)
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd" >
<suite name="Suite1" verbose="1" >
<listeners>
<listener class-name="testng.Transform2"/>
</listeners>
<test verbose="2" preserve-order="true" name="Test">
<classes>
<class name="testng.TransformFactory"></class>
</classes>
</test>
</suite>
涉及到的类:
package testng;
import org.testng.annotations.Test;
public class TestTransform {
private String str;
public TestTransform(String str){
this.str = str;
System.out.println("hello");
}
@Test
public void test(){
System.out.println("Test annotationTransformer!");
System.out.println("DataProviderName:"+str);
}
}
package testng;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import org.testng.annotations.IConfigurationAnnotation;
import org.testng.annotations.IDataProviderAnnotation;
import org.testng.annotations.IFactoryAnnotation;
import org.testng.annotations.ITestAnnotation;
import org.testng.internal.annotations.IAnnotationTransformer;
public class Transform2 implements IAnnotationTransformer{
public void transform(IConfigurationAnnotation iConfigurationAnnotation, Class aClass, Constructor constructor, Method method) {
}
public void transform(IDataProviderAnnotation iDataProviderAnnotation, Method method) {
if (iDataProviderAnnotation.getName().equals("tom"))
iDataProviderAnnotation.setParallel(true);
}
public void transform(IFactoryAnnotation iFactoryAnnotation, Method method) {
iFactoryAnnotation.setDataProvider("data");
}
public void transform(ITestAnnotation iTestAnnotation, Class aClass, Constructor constructor, Method method) {
}
}
package testng;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Factory;
public class TransformFactory {
@Factory(dataProvider = "tom")
public Object[] transformFac(String str){
Object[] objects = new Object[1];
for(int i=0;i<1;i++){
TestTransform testTransform = new TestTransform(str);
objects[i] = testTransform;
}
return objects;
}
@DataProvider(name = "tom")
public Object[][] tom(){
return new Object[][]{new Object[]{"tom"}};
}
@DataProvider(name = "data")
public Object[][] data(){
return new Object[][]{new Object[]{"data"}};
}
}
- 加一些逻辑的判断,哪些需要执行,那些不必。
我们还是先看xml文件:
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd" >
<suite name="Suite1" verbose="1" >
<listeners>
<listener class-name="hebu.c.down.HookaleDemo"></listener>
</listeners>
<test name="Nopackage" >
<classes>
<class name="hebu.c.down.Demo1" />
</classes>
</test>
</suite>
package hebu.c.down;
import static org.testng.Assert.assertEquals;
import org.testng.annotations.Test;
public class Demo1 {
@Test
public void test1() {
System.out.println("test1开始执行");
assertEquals(1,1);
}
@Test
public void test2() {
assertEquals(2,1);
}
}
package hebu.c.down;
import org.testng.IHookCallBack;
import org.testng.IHookable;
import org.testng.ITestResult;
import org.testng.internal.ConstructorOrMethod;
public class HookaleDemo implements IHookable{
@Override
public void run(IHookCallBack callBack, ITestResult testResult) {
ConstructorOrMethod method = testResult.getMethod().getConstructorOrMethod();
System.out.println("将要执行的方法名称: " + method.getName());
callBack.runTestMethod(testResult);
System.out.println("测试用例执行结束");
}
}
IReporter接口
举一个例子吧,包含他的基本使用,以及参数的用法。
package hebu.c.down;
import java.util.List;
import java.util.Map;
import org.testng.IReporter;
import org.testng.ISuite;
import org.testng.ISuiteResult;
import org.testng.ITestContext;
import org.testng.xml.XmlSuite;
public class Reporter implements IReporter{
@Override
public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
for(ISuite iSuite:suites) {
Map<String, ISuiteResult> iSuiteResultMap = iSuite.getResults();
System.out.println("获取所有的执行方法:" + iSuite.getAllInvokedMethods());
System.out.println("suit名称:" + iSuite.getName());
System.out.println("输出路径" + iSuite.getOutputDirectory());
for(ISuiteResult iSuiteResult : iSuiteResultMap.values()) {
ITestContext iTestContext = iSuiteResult.getTestContext();
System.out.println("成功的测试用例:" + iTestContext.getPassedTests().size());
}
}
}
}
package hebu.c.down;
import static org.testng.Assert.assertEquals;
import org.testng.annotations.Test;
public class Demo1 {
@Test
public void test1() {
System.out.println("test1开始执行");
assertEquals(1,1);
}
@Test
public void test2() {
assertEquals(2,1);
}
}
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd" >
<suite name="Suite1" verbose="1" >
<listeners>
<listener class-name="hebu.c.down.Reporter"></listener>
</listeners>
<test name="Nopackage" >
<classes>
<class name="hebu.c.down.Demo1" />
</classes>
</test>
</suite>
知道其参数的含义,我们还可以介绍一个它的应用:将所有的用力结果存储,并将其按照执行时间递增的存放在txt文件中: 只需要改变Reporter类:
package hebu.c.down ;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.testng.IReporter;
import org.testng.IResultMap;
import org.testng.ISuite;
import org.testng.ISuiteResult;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.xml.XmlSuite;
public class Reporter implements IReporter {
@Override
public void generateReport(List<XmlSuite> xmlSuites,
List<ISuite> suites,
String outputDirectory) {
List<ITestResult> list = new ArrayList<ITestResult>();
for (ISuite suite : suites) {
System.out.println(suite.getName());
Map<String, ISuiteResult> suiteResults = suite.getResults();
for (ISuiteResult suiteResult : suiteResults.values()) {
ITestContext testContext = suiteResult.getTestContext();
IResultMap passedTests = testContext.getPassedTests();
IResultMap failedTests = testContext.getFailedTests();
IResultMap skippedTests = testContext.getSkippedTests();
IResultMap failedConfig = testContext.getFailedConfigurations();
list.addAll(this.listTestResult(passedTests));
list.addAll(this.listTestResult(failedTests));
list.addAll(this.listTestResult(skippedTests));
list.addAll(this.listTestResult(failedConfig));
}
}
this.sort(list);
this.outputResult(list, outputDirectory + "/test.txt");
}
private ArrayList<ITestResult> listTestResult(IResultMap resultMap) {
Set<ITestResult> results = resultMap.getAllResults();
return new ArrayList<ITestResult>(results);
}
private void sort(List<ITestResult> list) {
Collections.sort(list, new Comparator<ITestResult>() {
@Override
public int compare(ITestResult r1, ITestResult r2) {
if (r1.getStartMillis() > r2.getStartMillis()) {
return 1;
} else {
return -1;
}
}
});
}
private void outputResult(List<ITestResult> list, String path) {
try {
BufferedWriter output = new BufferedWriter(new FileWriter(new File(path)));
StringBuffer sb = new StringBuffer();
for (ITestResult result : list) {
if (sb.length() != 0) {
sb.append("\r\n");
}
sb.append(result.getTestClass().getRealClass().getName()).append(" ")
.append(result.getMethod().getMethodName()).append(" ")
.append(this.formatDate(result.getStartMillis())).append(" ")
.append(this.getStatus(result.getStatus()));
}
output.write(sb.toString());
output.flush();
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private String getStatus(int status) {
String statusString = null;
switch (status) {
case 1:
statusString = "SUCCESS";
break;
case 2:
statusString = "FAILURE";
break;
case 3:
statusString = "SKIP";
break;
default:
break;
}
return statusString;
}
private String formatDate(long date) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return formatter.format(date);
}
}
执行后,刷新项目,在test-output文件夹中多了一个txt文件,内容如下:
ITestListener接口
一共由两种实现方式: 第一种,实现一个接口: 还是举例子吧,呜呜呜,我只会举例子,我什么都不懂!!
package hebu.c.down;
import org.testng.IResultMap;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestNGMethod;
import org.testng.ITestResult;
public class TestListener1 implements ITestListener{
@Override
public void onTestSuccess(ITestResult result) {
System.out.println(result.getName()+ "_" + result.getInstanceName() + "执行成功了");
}
@Override
public void onTestFailure(ITestResult result) {
System.out.println(result.getName()+ "_" + result.getInstanceName() + "执行失败....." + "需要截屏!!");
}
@Override
public void onFinish(ITestContext context) {
System.out.println("所有的测试用例执行完成。");
System.out.println("失败的:" + context.getFailedTests().size());
ITestNGMethod[] methods = context.getAllTestMethods();
IResultMap fail = context.getFailedTests();
for(ITestNGMethod m : methods) {
System.out.println(m.getInstance().toString() + "." + m.getMethodName());
}
}
}
这次我们没有在xml文件中设置,而是通过注解。
package hebu.c.down;
import static org.testng.Assert.assertEquals;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
@Listeners(TestListener1.class)
public class DemoForTestListener {
@Test
public void test1() {
System.out.println("test1");
}
@Test
public void test2() {
System.out.println("test222");
}
@Test
public void test3() {
System.out.println("test3333");
}
@Test
public void test4() {
System.out.println("test4");
assertEquals(1,2);
}
@Test
public void test5() {
System.out.println("test5");
assertEquals(1,6);
}
}
效果如下:
补充
在@Listeners 中添加监听器跟在 testng.xml 添加监听器的不同之处在于,它不能添加 IAnnotationTransformer 和 IAnnotationTransformer2 监听器 (那个,不叫这个2了)。原因是因为这两种监听器必须在更早的阶段添加到 TestNG 中才能实施修改注释的操作,所以它们只能在 testng.xml 添加。
第二种:继承一个类
package hebu.c.down;
import org.testng.annotations.Test;
import org.testng.AssertJUnit;
import static org.testng.Assert.assertEquals;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
@Listeners({TestListener2.class, TestListener3.class})
public class DemoForTestListener {
@Test
public void test1() {
System.out.println("test1");
}
@Test
public void test2() {
System.out.println("test222");
}
@Test
public void test3() {
System.out.println("test3333");
}
@Test
public void test4() {
System.out.println("test4");
AssertJUnit.assertEquals(1,2);
}
@Test
public void test5() {
System.out.println("test5");
AssertJUnit.assertEquals(1,6);
}
}
package hebu.c.down;
import java.util.List;
import org.testng.IResultMap;
import org.testng.ITestContext;
import org.testng.ITestNGMethod;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter;
public class TestListener2 extends TestListenerAdapter{
@Override
public void onFinish(ITestContext context) {
System.out.println("所有的测试用例执行完成。");
ITestNGMethod[] methods = this.getAllTestMethods();
List<ITestResult> fail = this.getFailedTests();
List<ITestResult> pass = this.getPassedTests();
System.out.println("共" + methods.length + " 成功的" + pass.size() + "失败的" + fail.size());
}
}
package hebu.c.down;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter;
public class TestListener3 extends TestListenerAdapter{
@Override
public void onTestSuccess(ITestResult tr) {
System.out.println(tr.getName()+ "_" + tr.getInstanceName() + "执行成功了");
}
@Override
public void onTestFailure(ITestResult tr) {
System.out.println(tr.getName()+ "_" + tr.getInstanceName() + "执行失败....." + "需要截屏!!");
}
}
效果:
注意:
- 继承的类已经有一些方法,比如onFinish中的一些,我们的onTestSuccess、onTestFailure就需要写在另一个java文件中了。否则会打印出的全是0。。。
- 除了在xml中添加两个listener, 注解方式@外,还可在类中添加:
@BeforeSuite
public void addListener(ITestContext context) {
TestRunner runner = (TestRunner) context;
runner.addListener(new TestListener2());
runner.addListener(new TestListener3());
}
|