文章目录
一、 用到的工具框架
TestNG(测试框架):https://testng.org/
ExtentReports(测试报告框架):https://www.extentreports.com/
Selenium(WEB自动化工具):https://www.selenium.dev/
Jsoup(Http工具):https://jsoup.org/
1、TestNG支持的注解
@BeforeSuite @AfterSuite @BeforeTest @AfterTest @BeforeGroups @AfterGroups @BeforeClass @AfterClass @BeforeMethod @AfterMethod | TestNG类的配置信息: @BeforeSuite: 带注解的方法将在此套件中的所有测试运行之前运行。 @AfterSuite: 带注解的方法将在此套件中的所有测试运行之后运行。 @BeforeTest: 带注解的方法将在测试类内部测试方法运行之前运行。 @AfterTest: 带注解的方法将在测试类内部测试方法运行之后运行。 @BeforeGroups: 带注解的方法带在任何一个组的第一个测试方法运行之前运行。 @AfterGroups: 带注解的方法带在任何一个组的第一个测试方法运行之后运行。 @BeforeClass: 带注解的方法将在当前类中的第一个测试方法运行之前运行。 @AfterClass: 带注解的方法将在当前类中的第一个测试方法运行之后运行。 @BeforeMethod: 带注解的方法将在每个测试方法运行之前运行。 @AfterMethod: 带注解的方法将在每个测试方法运行之后运行。 在TestNG类的父类中注解的行为 注解放在TestNG类的父类上时,上面的注解也会被继承。例如,在一个公共父类中集中多个测试类的测试配置是很有用的。 TestNG保证“@Before”方法的继承顺序(父类优先,然后向下继承链),和“@After”方法以相反的顺序(向上继承链)。 | |
alwaysRun | 对于before方法(beforeSuite, beforeTest, beforeTestClass和beforeTestMethod,除了beforeGroups):如果设置为true,不管它属于哪个组,都会运行此方法。 对于after方法(afterSuite, afterClass,…):如果设置为true,即使前边一个或多个方法失败或跳过,该方法也会运行。 | |
dependsOnGroups | 此方法所依赖的组列表。 | |
dependsOnMethods | 此方法依赖的方法列表。 | |
enabled | 是否启用该类/方法上的方法。 | |
groups | 该类/方法所属的组列表。 | |
inheritGroups | 如果为true,该方法将属于在类级别的@Test注释中指定的组。 | |
onlyForGroups | 只适用于@BeforeMethod和@AfterMethod。 如果指定,则只有当对应的测试方法属于列出的组之一时,才会调用此setup/teardown方法。 | |
@DataProvider | 为测试方法提供数据的方法。注解的方法必须返回一个Object[][],并且每个Object[]可以作为测试方法的参数列表。 需要从DataProvider接收数据的@Test方法需要使用与该注解名称相同的DataProvider名称。 | |
name | The name of this data provider. If it's not supplied, the name of this data provider will automatically be set to the name of the method. | |
parallel | If set to true, tests generated using this data provider are run in parallel. Default value is false. | |
@Factory | 设置data provider的名称。 如果没有设置,则默认使用方法名作为名称。 | |
@Listeners | 为测试类上设置监听器。 | |
value | 继承org.testng.ITestNGListener接口的类数组。 | |
@Parameters | 描述如何将参数传递给@Test方法。 | |
value | 为当前方法设置参数列表。 | |
@Test | 将类或方法设置为测试的一部分。 | |
alwaysRun | 如果设置为true,即使它依赖的方法执行失败,也将会继续运行。 | |
dataProvider | 为当前测试方法设置 data provider的名字。 | |
dataProviderClass | 设置data provider的提供类,如果没有设置,则在当前类和父类上查找;如果设置了,则会在对应类上查找 ,并具data provider的方法必须为静态方法。 | |
dependsOnGroups | 设置当前方法依赖的组列表。 | |
dependsOnMethods | 当前方法依赖的方法列表。 | |
description | 当前方法的内容描述 | |
enabled | 设计当前类或方法是否可用。 | |
expectedExceptions | 为测试方法设置异常列表,如果没有设置异常或抛出的异常与列表不一样,该方法将会运行失败。 | |
groups | The list of groups this class/method belongs to. | |
invocationCount | 调用此方法的次数。 | |
invocationTimeOut | 为测试方法设置最大的执行时间,如果没有指定,则会忽略该参数。 | |
priority | 设置测试方法的优先级,数值小的优先执行。 | |
successPercentage | 预测成功执行的百分比。 | |
singleThreaded | 如果设置为true,这个测试类上的所有方法都保证在同一个线程中运行,即使测试当前正在使用parallel="methods"运行。 这个属性只能在类级别使用,如果在方法级别使用,它将被忽略。 注意:这个属性过去被称为sequential(现在已弃用)。 | |
timeOut | 设置当前测试执行的最大毫秒数。 | |
threadPoolSize | 此方法的线程池的大小。 该方法将从由invocationCount指定的多个线程调用。 注意:如果没有指定invocationCount,该属性将被忽略 |
2、ExtentReports
ExtentReports 是一个用于生成自动化测试报告的库。报告中会详细记录系统或应用程序的消息或事件对象。 其分为专业版(Professi onal)和社区版(Community),专业版需要收费,而社区版为开源的。
Extent Reporting的TestNG适配器实现TestNG的ITestListener或IReporter接口,其包括了4个实现类。
1)ExtentITestListenerAdapter:继承ITestListener,在测试方法级别构建动态测试报告。
2)ExtentITestListenerClassAdapter:继承ITestListener,在测试类和测试方法级别构建动态测试报告。
3)ExtentIReporterSuiteListenerAdapter:继承IReporter,在测试套和测试方法级别构建静态测试报告。
4)ExtentIReporterSuiteClassListenerAdapter:继承IReporter,在测试套、测试类和测试方法级别构建静态测试报告。该监听器生成的测试报告信息最为丰富。
ExtentReports 5的社区的测试报告只支持Spark、klov、json,ExtentReports 4除了支持上边三种,还支持V3 HTMl、Email等,所以本文使用ExtentReports 4版本。
二、创建Maven工程
1、maven工程pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.penngo.test</groupId>
<artifactId>testng_extentreports</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<java.version>11</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
</dependency>
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>4.1.7</version>
<scope>system</scope>
<systemPath>${pom.basedir}/libs/extentreports-4.1.7.jar</systemPath>
</dependency>
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports-testng-adapter</artifactId>
<version>1.0.7</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.2.1</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.15.1</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.36</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.80</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>alimaven</id>
<name>aliyun maven</name>
<url>https://maven.aliyun.com/repository/public/</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.2</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<argLine>-Dfile.encoding=UTF-8</argLine>
<encoding>UTF-8</encoding>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/testng_test.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
</project>
2、Api接口测试(结合Jsoup使用)
ApiTest.java
package com.penngo.test;
import com.alibaba.fastjson.JSONObject;
import com.aventstack.extentreports.testng.listener.ExtentIReporterSuiteClassListenerAdapter;
import com.aventstack.extentreports.testng.listener.ExtentITestListenerClassAdapter;
import org.jsoup.Jsoup;
import org.testng.Assert;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
//@Listeners(ExtentITestListenerAdapter.class)
//@Listeners(ExtentITestListenerClassAdapter.class)
//@Listeners(ExtentIReporterSuiteListenerAdapter.class)
//@Listeners(ExtentIReporterSuiteClassListenerAdapter.class)
@Test(description="接口测试", testName ="接口测试test",suiteName = "接口测试suite")
public class ApiTest {
@Test(description="接口-广州天气",testName ="接口-广州天气test",suiteName = "接口-广州天气suite")
public void testApiWeather(){
try{
String json = Jsoup.connect("http://www.weather.com.cn/data/cityinfo/101280101.html").execute().body();
System.out.println(json);
JSONObject jsonObject = JSONObject.parseObject(json);
Assert.assertNotNull(jsonObject);
JSONObject weatherinfo = jsonObject.getJSONObject("weatherinfo");
Assert.assertEquals("广州", weatherinfo.getString("city"));
}
catch(Exception e){
e.printStackTrace();
}
}
}
3、网页测试(结合Selenium库使用)
PageTest.java
package com.penngo.test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.time.Duration;
import java.util.List;
import java.util.logging.Level;
@Test(description="页面")
public class PageTest {
protected WebDriver driver;
static {
// 关闭控制selenium命令行日志输出
System.setProperty("webdriver.chrome.silentOutput", "true");
java.util.logging.Logger.getLogger("org.openqa.selenium").setLevel(Level.WARNING);
String os = System.getProperty("os.name").toLowerCase();
// linux上运行
if(os.indexOf("windows") == -1){
System.setProperty("webdriver.chrome.driver", "webdriver/chromedriver");
}
// window上运行,本机调试
else{
System.setProperty("webdriver.chrome.driver", "../webdriver/chromedriver.exe");
}
}
@Test(description="页面-java常用类库")
public void testPageJava() {
driver.get("https://21doc.net/java/awesomejava");
List<WebElement> list = driver.findElements(By.cssSelector(".row .col-sm-9 h3"));
Assert.assertEquals(list.size() , 70);
WebElement element0 = list.get(0);
System.out.println("element0.getText():" + element0.getText());
Assert.assertEquals("对象映射",element0.getText());
WebElement element1 = list.get(1);
System.out.println("element1.getText():" + element1.getText());
Assert.assertEquals("构建工具",element1.getText());
WebElement element2 = list.get(2);
System.out.println("element2.getText():" + element2.getText());
Assert.assertEquals("字节码操作",element2.getText());
}
@BeforeClass
public void setUpAll(){
System.out.println("setUpAll===============");
System.setProperty("webdriver.chrome.driver", "webdriver/chromedriver.exe");
ChromeOptions options = new ChromeOptions();
options.setHeadless(false); // 是否显示浏览器
options.setAcceptInsecureCerts(true);
driver = new ChromeDriver(options);
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(60));
driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(60));
}
@AfterClass
public void tearDownAll(){
System.out.println("tearDownAll===============");
driver.quit();
}
}
4、Extent Reports配置
1)extent.properties
extent.reporter.html.start=true
extent.reporter.html.out=test-output/ReportHTML.html
extent.reporter.klov.start=true
extent.reporter.klov.config=src/test/resources/klov.properties
extent.reporter.spark.start=true
extent.reporter.spark.config=
extent.reporter.spark.out=test-output/SparkHTML.html
2)klov服务器端配置
klov.properties
project.name=test_project
report.name=test_project
mongodb.host=localhost
mongodb.port=27017
mongodb.uri=mongodb://localhost:27017
klov.project.name=test_project
klov.report.name=test_report
klov.host=http://localhost
klov.port=80
5、TestNG配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="test测试">
<listeners>
<!-- <listener class-name="com.aventstack.extentreports.testng.listener.ExtentITestListenerAdapter"></listener>-->
<listener class-name="com.aventstack.extentreports.testng.listener.ExtentITestListenerClassAdapter"></listener>
<!-- <listener class-name="com.aventstack.extentreports.testng.listener.ExtentIReporterSuiteListenerAdapter"></listener>-->
<!-- <listener class-name="com.aventstack.extentreports.testng.listener.ExtentIReporterSuiteClassListenerAdapter"></listener>-->
</listeners>
<test name="test测试类">
<classes>
<class name="com.penngo.test.PageTest" />
<class name="com.penngo.test.ApiTest" />
</classes>
</test>
</suite>
6、下载webdriver
chromedriver下载地址:https://chromedriver.storage.googleapis.com/index.html
geckodriver(firefox)下载地址:https://github.com/mozilla/geckodriver
需要下载与本地浏览器对应版本的webdriver,放与代码中配置的路径一致,本文使用chrome测试
// PageTest.java
static{
// ......
System.setProperty("webdriver.chrome.driver","webdriver/chromedriver.exe");
// .......
}
三、运行和ExtentReports测试报告
1、运行测试
命令运行输入mvn package或mvn test
2、v3 html本地测试报告
3、spark html本地测试报告
4、klov测试报告
需要先运行klov服务器,本文使用klov_0.2.8版本服务器端
klov服务器端查看测试报告