一:pom依赖引入
<!-- 设置自定义的监听类,代替默认的testng -->
<dependency>
<groupId>com.relevantcodes</groupId>
<artifactId>extentreports</artifactId>
<version>2.41.1</version>
</dependency>
<dependency>
<groupId>com.vimalselvam</groupId>
<artifactId>testng-extentsreport</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>3.0.6</version>
</dependency>
<!-- 依赖reportNg 关联testNg -->
<dependency>
<groupId>org.uncommons</groupId>
<artifactId>reportng</artifactId>
<version>1.1.4</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>4.2.2</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.testng/testng -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.10</version>
<scope>test</scope>
</dependency>
<!-- 日志工具包 1.2.17 log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--编译环境-->
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<xmlFileName>testng.xml</xmlFileName>
</properties>
二:测试插件配置
<!--插件配置-->
<build>
<!-- 配置插件 -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!-- java编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<!-- 跳过测试失败的,继续执行 -->
<testFailureIgnore>true</testFailureIgnore>
<suiteXmlFiles>
<suiteXmlFile>${xmlFileName}</suiteXmlFile>
</suiteXmlFiles>
<properties>
<property>
<name>usedefaultlisteners</name>
<value>false</value>
</property>
<property>
<name>listener</name>
<value>com.testNg.testNg.versionone.ExtentTestNGIReporterListener</value>
</property>
</properties>
<forkMode>never</forkMode>
<workingDirectory>target/</workingDirectory>
<!-- <reportsDirectory>report/</reportsDirectory> -->
</configuration>
</plugin>
</plugins>
</build>
三:测试类编写
<!--测试类-->
public class TestMethodsDemo {
@BeforeSuite
public void beforesuit() {
System.out.println("beforesuit----");
}
@BeforeClass
public void beforeclass() {
System.out.println("beforeclass----");
}
@BeforeTest
public void testSuit() {
System.out.println("beforetest----");
}
@BeforeMethod
public void BeforeMethod() {
System.out.println("BeforeMethod----");
}
@Test(groups = { "运算" }, priority = 4)
public void test1() {
Assert.assertEquals(1, 1);
}
@Test(groups = { "运算" }, priority = 3)
public void test2() {
Assert.assertEquals(2, 2);
}
@Test(groups = { "动物" }, priority = 2, enabled = false)
public void test3() {
Assert.assertEquals("bbb", "bbb");
}
@Test(groups = { "动物", "运算" }, priority = 0, enabled = false)
public void logDemo() {
Reporter.log("这是我们自己写的日志");
throw new RuntimeException("运行时异常");
}
@Test(dependsOnMethods = { "login" })
public void mainTest() {
Reporter.log("登录成功");
System.out.println("login登录成功");
}
@Test
public void login() {
Reporter.log("请求登录");
System.out.println("请求登录");
}
@AfterSuite
public void AfterSuite() {
System.out.println("AfterSuite----");
}
@AfterClass
public void AfterClass() {
System.out.println("AfterClass----");
}
@AfterTest
public void AfterTest() {
System.out.println("beforetest----");
}
@AfterMethod
public void AfterMethod() {
System.out.println("AfterMethod----");
}
}
四:testng.xml编写
主要部件:suit test class listener
当测试用例所需参数很少时,还可以将测试参数写在testng.xml里,也可以指定需要运行的测试case,或者测试class
<!--testng.xml文件-->
<?xml version="1.0" encoding="UTF-8"?>
<suite name="Test Automation" parallel="tests">
<test thread-count="5" name="Test Cases">
<classes>
<class name="com.testNg.testNg.versionone.TestMethodsDemo"/>
</classes>
</test>
<!-- 这是reportNG的监听类
<listeners>
<listener class-name="org.uncommons.reportng.HTMLReporter"></listener>
<listener class-name="org.uncommons.reportng.JUnitXMLReporter"></listener>
</listeners> -->
<!-- 自定义的监听类 -->
<listeners>
<listener class-name="com.testNg.testNg.versionone.ExtentTestNGIReporterListener"></listener>
</listeners>
</suite>
五:自定义的监听工具
直接使用默认的监听工具会出现乱码以及页面显示错误等问题,通过实现IReporter接口开发监听接口 网上找的监听类实现IReporter接口:
public class ExtentTestNGIReporterListener implements IReporter {
//生成的路径以及文件名
private static final String OUTPUT_FOLDER = "report/";
private static final String FILE_NAME = "ExtentReport.html";
private ExtentReports extent;
@Override
public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
init();
boolean createSuiteNode = false;
if(suites.size()>1){
createSuiteNode=true;
}
for (ISuite suite : suites) {
Map<String, ISuiteResult> result = suite.getResults();
//如果suite里面没有任何用例,直接跳过,不在报告里生成
if(result.size()==0){
continue;
}
//统计suite下的成功、失败、跳过的总用例数
int suiteFailSize=0;
int suitePassSize=0;
int suiteSkipSize=0;
ExtentTest suiteTest=null;
//存在多个suite的情况下,在报告中将同一个一个suite的测试结果归为一类,创建一级节点。
if(createSuiteNode){
suiteTest = extent.createTest(suite.getName()).assignCategory(suite.getName());
}
boolean createSuiteResultNode = false;
if(result.size()>1){
createSuiteResultNode=true;
}
for (ISuiteResult r : result.values()) {
ExtentTest resultNode;
ITestContext context = r.getTestContext();
if(createSuiteResultNode){
//没有创建suite的情况下,将在SuiteResult的创建为一级节点,否则创建为suite的一个子节点。
if( null == suiteTest){
resultNode = extent.createTest(r.getTestContext().getName());
}else{
resultNode = suiteTest.createNode(r.getTestContext().getName());
}
}else{
resultNode = suiteTest;
}
if(resultNode != null){
resultNode.getModel().setName(suite.getName()+" : "+r.getTestContext().getName());
if(resultNode.getModel().hasCategory()){
resultNode.assignCategory(r.getTestContext().getName());
}else{
resultNode.assignCategory(suite.getName(),r.getTestContext().getName());
}
resultNode.getModel().setStartTime(r.getTestContext().getStartDate());
resultNode.getModel().setEndTime(r.getTestContext().getEndDate());
//统计SuiteResult下的数据
int passSize = r.getTestContext().getPassedTests().size();
int failSize = r.getTestContext().getFailedTests().size();
int skipSize = r.getTestContext().getSkippedTests().size();
suitePassSize += passSize;
suiteFailSize += failSize;
suiteSkipSize += skipSize;
if(failSize>0){
resultNode.getModel().setStatus(Status.FAIL);
}
resultNode.getModel().setDescription(String.format("Pass: %s ; Fail: %s ; Skip: %s ;",passSize,failSize,skipSize));
}
buildTestNodes(resultNode,context.getFailedTests(), Status.FAIL);
buildTestNodes(resultNode,context.getSkippedTests(), Status.SKIP);
buildTestNodes(resultNode,context.getPassedTests(), Status.PASS);
}
if(suiteTest!= null){
suiteTest.getModel().setDescription(String.format("Pass: %s ; Fail: %s ; Skip: %s ;",suitePassSize,suiteFailSize,suiteSkipSize));
if(suiteFailSize>0){
suiteTest.getModel().setStatus(Status.FAIL);
}
}
}
// for (String s : Reporter.getOutput()) {
// extent.setTestRunnerOutput(s);
// }
extent.flush();
}
private void init() {
//文件夹不存在的话进行创建
File reportDir= new File(OUTPUT_FOLDER);
if(!reportDir.exists()&& !reportDir .isDirectory()){
reportDir.mkdir();
}
ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter(OUTPUT_FOLDER + FILE_NAME);
// 设置静态文件的DNS
//重点:怎么样解决cdn.rawgit.com访问不了的情况
htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS);
htmlReporter.config().setDocumentTitle("TestNG自动化测试报告");
htmlReporter.config().setReportName("TestNG自动化测试报告");
htmlReporter.config().setChartVisibilityOnOpen(true);
htmlReporter.config().setTestViewChartLocation(ChartLocation.TOP);
htmlReporter.config().setTheme(Theme.STANDARD);
htmlReporter.config().setCSS(".node.level-1 ul{ display:none;} .node.level-1.active ul{display:block;}");
extent = new ExtentReports();
extent.attachReporter(htmlReporter);
extent.setReportUsesManualConfiguration(true);
}
private void buildTestNodes(ExtentTest extenttest, IResultMap tests, Status status) {
//存在父节点时,获取父节点的标签
String[] categories=new String[0];
if(extenttest != null ){
List<TestAttribute> categoryList = extenttest.getModel().getCategoryContext().getAll();
categories = new String[categoryList.size()];
for(int index=0;index<categoryList.size();index++){
categories[index] = categoryList.get(index).getName();
}
}
ExtentTest test;
if (tests.size() > 0) {
//调整用例排序,按时间排序
Set<ITestResult> treeSet = new TreeSet<ITestResult>(new Comparator<ITestResult>() {
@Override
public int compare(ITestResult o1, ITestResult o2) {
return o1.getStartMillis()<o2.getStartMillis()?-1:1;
}
});
treeSet.addAll(tests.getAllResults());
for (ITestResult result : treeSet) {
Object[] parameters = result.getParameters();
String name="";
//如果有参数,则使用参数的toString组合代替报告中的name
for(Object param:parameters){
name+=param.toString();
}
if(name.length()>0){
if(name.length()>50){
name= name.substring(0,49)+"...";
}
}else{
name = result.getMethod().getMethodName();
}
if(extenttest==null){
test = extent.createTest(name);
}else{
//作为子节点进行创建时,设置同父节点的标签一致,便于报告检索。
test = extenttest.createNode(name).assignCategory(categories);
}
//test.getModel().setDescription(description.toString());
//test = extent.createTest(result.getMethod().getMethodName());
for (String group : result.getMethod().getGroups())
test.assignCategory(group);
List<String> outputList = Reporter.getOutput(result);
for(String output:outputList){
//将用例的log输出报告中
test.debug(output);
}
if (result.getThrowable() != null) {
test.log(status, result.getThrowable());
}
else {
test.log(status, "Test " + status.toString().toLowerCase() + "ed");
}
test.getModel().setStartTime(getTime(result.getStartMillis()));
test.getModel().setEndTime(getTime(result.getEndMillis()));
}
}
}
private Date getTime(long millis) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(millis);
return calendar.getTime();
}
}
生成报告截图:
运行:maven项目直接可以在命令行里输入 mvn test 它会自动执行测试,并将测试报告输出到指定目录下,后面会介绍Jenkins集成
关于testNg的教程,后面也会给出,TestNg测试框架常用的元素
可以了解下,依赖,分组,异常等,其中依赖用最频繁