Selenium——TestNG高级应用浅析


内容引入:如何判断测试样例执行完,并查看测试报告?

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共享数据

  1. 可以在类中定义变量,那么类中的所有方法都可以使用。
  2. 可以使用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方法的执行状态等信息

  1. 每执行一次测试方法,就会执行一次@AfterMethod方法。
  2. ITestResult.getThrowable() 测试的报错信息
  3. 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()+ "--失败了");
		}
	}
}

结果如下:
在这里插入图片描述

监听器

  1. 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) {
		//@Test的测试方法执行5次。 
		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>

  1. 与上例重名,与上述的那个不同的是,导入的包不一样。上例导的包为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"))  //匹配名为tom的DataProvider
            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"}};
    }
}

  1. 加一些逻辑的判断,哪些需要执行,那些不必。
    我们还是先看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() + "执行失败....." + "需要截屏!!");
	  }
}

效果:
在这里插入图片描述

注意:

  1. 继承的类已经有一些方法,比如onFinish中的一些,我们的onTestSuccess、onTestFailure就需要写在另一个java文件中了。否则会打印出的全是0。。。
  2. 除了在xml中添加两个listener, 注解方式@外,还可在类中添加:
	@BeforeSuite
	public void addListener(ITestContext context) {
		TestRunner runner = (TestRunner) context;
		runner.addListener(new TestListener2());
		runner.addListener(new TestListener3());
	}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Xuhx&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值