Java测试框架-TestNG
一、TestNG简介
TestNG是一个受JUnit和NUnit启发的测试框架,但引入了一些使其更强大且更易于使用的新功能,例如:
- 注解。
- 在具有各种可用策略的任意大线程池中运行测试(所有方法都在其自己的线程中,每个测试类一个线程,等等)。
- 测试您的代码是多线程安全的。
- 灵活的测试配置。
- 支持数据驱动的测试(使用@DataProvider)。
- 支持参数。
- 强大的执行模型(不再需要TestSuite)。
- 由各种工具和插件(Eclipse,IDEA,Maven等)支持。
- 嵌入BeanShell以获得更高的灵活性。
- 用于运行时和日志记录的默认JDK函数(无依赖项)。
- 应用服务器测试的相关方法。
TestNG旨在涵盖所有类别的测试:单元,功能,端到端,集成等。
二、TestNG使用
第一步:准备环境
jdk1.8
Maven
IDEA
第二步:创建maven工程
第三步:引入TestNG
依赖
在pom.xml
文件中的<dependencies> </dependencies>
标签中添加以下依赖:
<!-- https://mvnrepository.com/artifact/org.testng/testng -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
<scope>test</scope>
</dependency>
第三步:创建一个测试类
1)在src/test/java
文件夹下创建一个包Package
:com.desire.testcase
2)在创建的包下面再创建一个Java Class
类:TestCase
3)在创建的测试类中,添加测试方法:testDemo
,需要在该方法上添加@Test
注解
package com.desire.testcase;
import org.testng.annotations.Test;
public class TestCase {
@Test
public void testDemo() {
String msg = "登录成功";
System.out.println(msg);
assert msg.equals("登录成功");
}
}
目录结构:
第四步:运行测试方法
运行1:在创建的测试类中右击Run 'TestCase'
进行运行测试,测试结果如下:
运行2:使用testng.xml
进行运行
在工程根目录下创建testng.xml
文件(在PyCharm
中可以安装插件Create TestNG XML
,然后在工程中右击就可以找到Create TestNG XML
选项,点击就会在工程根目录下创建testng.xml
)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="All Test Suite">
<test verbose="2" preserve-order="true" name="D:/IdeaProjects/testng">
<classes>
<class name="com.desire.testcase.TestCase">
<methods>
<include name="testDemo"/>
</methods>
</class>
<class name="com.desire.testcase.TestCase02">
<methods>
<include name="testDemo"/>
</methods>
</class>
</classes>
</test>
</suite>
运行:
1、在testng.xml
文件中右击Run 'D:/xxx/testng.xml'
进行运行。
2、通过命令行启动mvn clean test -D testng.xml
-D
:将在其中生成报告的目录(默认为test-output)。
需要在pom.xml
文件添加以下配置:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>//该文件位于工程根目录时,直接填写名字,其它位置要加上路径。
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
命令行运行后,会在target
目录下生成一个surefire-reports
测试报告目录,运行里面的index.html
即可看到测试报告。
运行的时候运行<classs>
标签中<class>
中的所有<methods>
三、TestNG注解
(1)标记为测试类或方法
1. @Test
:将类或方法标记为测试的一部分。
@Test
public void testDemo() {
String msg = "登录成功";
System.out.println(msg);
assert msg.equals("登录成功");
}
属性 | 说明 |
| 提供一个false or true值,如果设置为true,则被标记的方法会永远被执行,即使被标记方法所依赖的方法执行失败了。 |
| 此属性的值为标记方法提供数据驱动的数据源 |
| 此属性指出提供数据驱动方法的所在类 |
| 此属性指出标记方法所依赖的组 |
| 此属性支持标记方法所依赖的方法 |
| 标记方法的描述信息 |
| 标记方法是否要执行,默认为true执行 |
| 指定标记方法返回的异常信息列表 |
| 指定标记方法归属于哪个组 |
| 指定标记方法超时时长 (in millisecs) |
| 被标记的方法会执行多次 |
| 启用多个线程执行被标记的方法,一般会与invocationCount一起使用 |
(2)前置/后置条件
1. @BeforeSuite
:带注释的方法将在该套件中的所有测试运行之前运行。
@BeforeSuite
public void beforeSuite() {
System.out.println("-->>beforeSuite:带注解的方法将在该套件中的所有测试运行之前运行。");
}
2. @AfterSuite
:带注解的方法将在运行此套件中的所有测试之后运行。
@AfterSuite
public void afterSuite(){
System.out.println("-->>afterSuite:带注解的方法将在运行此套件中的所有测试之后运行。");
}
3. @BeforeTest
:带注解的方法将在运行任何属于标记内的类的测试方法之前运行。
@BeforeTest
public void beforeTest(){
System.out.println("-->>beforeTest:带注解的方法将在运行任何属于<test>标记内的类的测试方法之前运行。");
}
4. @AfterTest
:带注解的方法将在所有属于标记内的类的测试方法运行后运行。
@AfterTest
public void afterTest(){
System.out.println("-->>afterTest:带注解的方法将在运行任何属于<test>标记内的类的测试方法之后运行。");
}
5. @BeforeGroups
:此配置方法将在其之前运行的组的列表。保证此方法可以在调用属于这些组中的任何一个的第一个测试方法之前不久运行。
注意:分组需要在测试方法上添加分组:@Test(groups = "1")
@BeforeGroups("1")
public void beforeGroups() {
System.out.println("-->>beforeGroups:此配置方法将在其之前运行的组的列表。保证此方法可以在调用属于这些组中的任何一个的第一个测试方法之前不久运行。");
}
6. @AfterGroups
:此配置方法将在其后运行的组的列表。保证在调用属于这些组中任何一个的最后一个测试方法后不久便可以运行该方法。
@AfterGroups("1")
public void afterGroups() {
System.out.println("-->>afterGroups:此配置方法将在其后运行的组的列表。保证在调用属于这些组中任何一个的最后一个测试方法后不久便可以运行该方法。");
}
7. @BeforeClass
:带注解的方法将在调用当前类中的第一个测试方法之前运行。
@BeforeClass
public void beforeClass() {
System.out.println("-->>beforeClass:带注解的方法将在调用当前类中的第一个测试方法之前运行。");
}
8. @AfterClass
:带注解的方法将在当前类中的所有测试方法运行之后运行。
@AfterClass
public void afterClass() {
System.out.println("-->>afterClass:带注解的方法将在当前类中的所有测试方法运行之后运行。");
}
9. @BeforeMethod
:带注解的方法将在每个测试方法之前运行。
@BeforeMethod
public void beforeMethod() {
System.out.println("-->>beforeMethod:带注解的方法将在每个测试方法之前运行。");
}
10. @AfterMethod
:带注解的方法将在每个测试方法之后运行。
@AfterMethod
public void afterMethod() {
System.out.println("-->>afterMethod:带注解的方法将在每个测试方法之后运行。");
}
执行结果如下:
-->>beforeSuite:带注解的方法将在该套件中的所有测试运行之前运行。
-->>beforeTest:带注解的方法将在运行任何属于<test>标记内的类的测试方法之前运行。
-->>beforeClass:带注解的方法将在调用当前类中的第一个测试方法之前运行。
-->>beforeGroups:此配置方法将在其之前运行的组的列表。保证此方法可以在调用属于这些组中的任何一个的第一个测试方法之前不久运行。
-->>beforeMethod:带注解的方法将在每个测试方法之前运行。
-->>testDemo:测试用例
-->>afterMethod:带注解的方法将在每个测试方法之后运行。
-->>afterGroups:此配置方法将在其后运行的组的列表。保证在调用属于这些组中任何一个的最后一个测试方法后不久便可以运行该方法。
-->>afterClass:带注解的方法将在当前类中的所有测试方法运行之后运行。
-->>afterTest:带注解的方法将在运行任何属于<test>标记内的类的测试方法之后运行。
-->>afterSuite:带注解的方法将在运行此套件中的所有测试之后运行。
===============================================
Default Suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================
Process finished with exit code 0
由测试执行结果可以看出这几个注解的执行顺序:
BeforeSuite
–>>BeforeTest
–>>BeforeClass
–>>BeforeGroups
–>>BeforeMethod
–>>测试方法
–>>AfterMethod
–>>AfterGroups
–>>AfterClass
–>>AfterTest
–>>AfterSuite
(3)testng数据驱动
1. @DataProvider
:将方法标记为为测试方法提供数据。
带注释的方法必须返回一个Object [][]
,其中可以为每个 Object []
分配测试方法的参数列表。想要从这个DataProvider
接收数据的@Test
方法需要使用一个等于这个注释名称的DataProvider
名称。
定义一个数据驱动方法
@DataProvider(name = "datas")
public Object[][] params() {
return new Object[][]{
//可以写多个值,没有限制
{"Desire", "男", 23},
{"Ronin", "男", 20},
{"Tomy", "女", 18}
};
}
使用这个数据驱动
使用的时候需要给注解@Test
添加dataProvider
参数,参数值就对应上面定义的数据驱动方法中@DataProvider
注解的name
值。
@Test(dataProvider = "datas")
public void testDemo(String name, String sex, int age) {
System.out.println(String.format("姓名:%s,性别:%s,年龄:%d", name, sex, age));
}
运行结果:
2. @Parameters
:描述如何将参数传递给@Test
方法。
语法:
- 在
java
类中定义参数名@Parameters({ "paraName" })
; - 在
TestNG.xml
中设置参数值<parameter name="paraName" value="paraValue"/>
注意: - 只有已使用
@Test or @Before/After or @Factory
注解的方法可以使用@Parameters
. - 参数有作用域,在
testng.xml
中,参数在<suite> or <test>
标签下赋值. 如果有同名参数,<test>
标签下参数优先级高.
1) 传一个参数:
@Parameters({"url"})
@Test
public void testDemo(String url) {
System.out.println(url);
}
在testng.xml
中的<suite>
标签中添加<parameter>
<suite name="All Test Suite">
<parameter name="url" value="http://localhost:8080/user/login"></parameter>
<test verbose="2" preserve-order="true" name="D:/IdeaProjects/testng">
<classes>
<class name="com.desire.testcase.TestCase03">
<methods>
<include name="testDemo"/>
</methods>
</class>
</classes>
</test>
</suite>
运行结果:
2) 传多个参数:
public class TestCase03 {
private static String loginUrl;
@Parameters({"host", "url"})
@BeforeMethod
public void beforeMethod(String host, String url) {
System.out.println("---BeforeMethod---");
System.out.println("host:" + host);
System.out.println("url:" + url);
loginUrl = host + url;
}
@Test
public void testDemo() {
System.out.println("---testDemo---");
System.out.println("loginUrl:" + loginUrl);
}
}
<suite name="All Test Suite">
<parameter name="host" value="http://localhost:8080"></parameter>
<parameter name="url" value="/user/login"></parameter>
<test verbose="2" preserve-order="true" name="D:/IdeaProjects/testng">
<classes>
<class name="com.desire.testcase.TestCase03">
<methods>
<include name="testDemo"/>
</methods>
</class>
</classes>
</test>
</suite>
运行结果:
3) 使用默认值@Optional
testng.xml
中无name="db"
的parameter
,testDemo
中直接读取默认值"mysql"
@Parameters({"db"})
@Test
public void testDemo(@Optional("mysql") String db) {
System.out.println("使用的数据库是:" + db);
}