介绍
TestNG是一个设计用来简化广泛的测试需求的测试框架,从单元测试(隔离测试一个类)到集成测试(测试由有多个类多个包甚至多个外部框架组成的整个系统,例如运用服务器)。
编写一个测试的过程有三个典型步骤:
①、编写测试的 业务逻辑并在代码中插入TestNG annotation
②、将测试信息添加到testng.xml文件或者build.xml中
③、运行TestNG
对比
①、TestNg更适合复杂的继承测试,Junit更适合隔离性比较强的单元测试。
②、比junit涵盖功能更全面,Testng可以通过注解去区分执行方法的先后和依赖关系,而junit做不到。
③、TestNg因为有xml文件,所以TestNg可以针对一组测试类共同测试,而junit只能一个类资源内部测试,相对比较耗时。
④、测试套件运行失败,JUnit 4会重新运行整个测试套件。TestNG运行失败时,会创建一个XML文件说明失败的测试,利用这个文件执行程序,就不会重复运行已经成功的测试。
参考:https://mkyong.com/unittest/junit-4-vs-testng-comparison/
准备
maven项目直接引入依赖:
<!-- https://mvnrepository.com/artifact/org.testng/testng -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.6.0</version>
<scope>test</scope>
</dependency>
使用
TestNG基本注解
注解 | 作用 |
---|---|
@Test | 标记一个类或方法作为测试的一部分 |
@BeforeMethod | 在每个@Test方法前都会运行 |
@AfterMethod | 在每个@Test方法后都会运行 |
@BeforeClass | 该方法在类运行前运行,且仅运行一次 |
@AfterClass | 该方法在类运行后运行,且仅运行一次 |
@BeforSuite | 测试套件,类运行前运行(@BeforeClass之前),可通过xml包裹多个测试类 |
@AfterSuite | 测试套件,类运行后运行(@AfterClass之后),可通过xml包裹多个测试类 |
执行顺序演示
import org.testng.annotations.*;
public class TestNGDemo {
@Test
public void test1() {
System.out.println("test1()执行了!");
}
@Test
public void test2() {
System.out.println("test2()执行了!");
}
@BeforeMethod
public void test3() {
System.out.println("BeforeMethod的test3()执行了!");
}
@AfterMethod
public void test4() {
System.out.println("AfterMethod的test4()执行了!");
}
@BeforeClass
public void test5() {
System.out.println("BeforeClass的test5()执行了!");
}
@AfterClass
public void test6() {
System.out.println("AfterClass的test6()执行了!");
}
@BeforeSuite
public void test7() {
System.out.println("BeforeSuite的test7()执行了!");
}
@AfterSuite
public void test8() {
System.out.println("AfterSuite的test8()执行了!");
}
}
执行结果:
BeforeSuite的test7()执行了!
BeforeClass的test5()执行了!
BeforeMethod的test3()执行了!
test1()执行了!
AfterMethod的test4()执行了!
BeforeMethod的test3()执行了!
test2()执行了!
AfterMethod的test4()执行了!
AfterClass的test6()执行了!
AfterSuite的test8()执行了!
测试套件
在前面的代码基础上,我们想只执行TestNGDemo类的test1()方法,可以在resources资源目录下新建个xml文件,如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="mySuite">
<test name="myName">
<classes>
<class name="com.dc.TestNGDemo">
<methods>
<!-- 仅包含TestNGDemo类中的test1()方法 -->
<include name="test1"></include>
<!-- 排除TestNGDemo类中的test2()方法 -->
<!--<exclude name="test2"></exclude>-->
</methods>
</class>
</classes>
</test>
</suite>
忽略测试
当我们不想要某个方法或类参与测试时,又不想动xml,我们可以为@Test注解加个属性值enabled=false,表示不参与测试。
import org.testng.annotations.*;
public class TestNGDemo {
@Test(enabled = false)
public void test1() {
System.out.println("test1()执行了!");
}
}
分组测试
基于方法的分组
import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
public class TestNGGroupDemo {
@Test(groups = "G1")
public void test1() {
System.out.println("G1的test1()执行了!");
}
@Test(groups = "G2")
public void test2() {
System.out.println("G2的test2()执行了!");
}
@Test(groups = "G1")
public void test3() {
System.out.println("G1的test3()执行了!");
}
@BeforeGroups("G1")
public void test4() {
System.out.println("G1分组的BeforeGroups的test4()执行了!");
}
@AfterGroups("G1")
public void test5() {
System.out.println("G1分组的AfterGroups的test5()执行了!");
}
@BeforeGroups("G2")
public void test6() {
System.out.println("G2分组的BeforeGroups的test6()执行了!");
}
@AfterGroups("G2")
public void test7() {
System.out.println("G2分组的AfterGroups的test7()执行了!");
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="mySuite2">
<test name="myName2">
<groups>
<run>
<include name="G1"></include>
</run>
</groups>
<classes>
<class name="com.dc.TestNGGroupDemo" />
</classes>
</test>
</suite>
执行结果:
G1分组的BeforeGroups的test4()执行了!
G1的test1()执行了!
G1的test3()执行了!
G1分组的AfterGroups的test5()执行了!
基于类的分组
import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
@Test(groups = "CT1")
public class TestNGGroupDemo {
@Test(groups = "G1")
public void test1() {
System.out.println("G1的test1()执行了!");
}
@Test(groups = "G2")
public void test2() {
System.out.println("G2的test2()执行了!");
}
@Test(groups = "G1")
public void test3() {
System.out.println("G1的test3()执行了!");
}
@BeforeGroups("G1")
public void test4() {
System.out.println("G1分组的BeforeGroups的test4()执行了!");
}
@AfterGroups("G1")
public void test5() {
System.out.println("G1分组的AfterGroups的test5()执行了!");
}
@BeforeGroups("G2")
public void test6() {
System.out.println("G2分组的BeforeGroups的test6()执行了!");
}
@AfterGroups("G2")
public void test7() {
System.out.println("G2分组的AfterGroups的test7()执行了!");
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="mySuite2">
<test name="myName2">
<groups>
<run>
<include name="CT1"></include>
</run>
</groups>
<classes>
<class name="com.dc.TestNGGroupDemo" />
</classes>
</test>
</suite>
执行结果:
G1分组的BeforeGroups的test4()执行了!
G1的test1()执行了!
G2分组的BeforeGroups的test6()执行了!
G2的test2()执行了!
G2分组的AfterGroups的test7()执行了!
G1的test3()执行了!
G1分组的AfterGroups的test5()执行了!
异常测试:
@Test(expectedExceptions = XXException.class)
当我们想要验证测试方法是否会出现预期异常,我们可以为@Test注解添加属性expectedExceptions,当属性值与实际异常相同时,会忽略,执行通过。反之没有出现指定异常时,TestNG会提示TestException。
-
未添加注解属性时:
-
添加了注解属性,且异常类匹配:
-
添加了注解属性,但异常类不匹配:
依赖测试:
@Test(dependsOnMethods = {“使用了@Test的别的方法名”})
可通过该注解进行方法的顺序关联,依赖关联。
例1:
通过dependsOnMethods依赖,将原本test1>test2>test3的顺序改为了test1>test3>test2。
import org.testng.annotations.Test;
public class TestNRelyDemo {
@Test
public void test1(){
System.out.println("test1()执行了!");
}
@Test(dependsOnMethods = "test3")
public void test2(){
System.out.println("test2()执行了!");
}
@Test(dependsOnMethods = "test1")
public void test3(){
System.out.println("test3()执行了!");
}
}
执行结果:
test1()执行了!
test3()执行了!
test2()执行了!
例2:
当被依赖的方法test1()执行失败,那么test2()、test3()都不会执行。
import org.testng.annotations.Test;
public class TestNRelyDemo {
@Test
public void test1(){
System.out.println("test1()执行了!");
throw new NullPointerException();
}
@Test(dependsOnMethods = "test3")
public void test2(){
System.out.println("test2()执行了!");
}
@Test(dependsOnMethods = "test1")
public void test3(){
System.out.println("test3()执行了!");
}
}
执行结果:
test1报错,后面依赖test1的方法直接忽略不执行。
参数化测试
@Parameters({“param1”,”param2”,......})
xml传参
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
public class TestNGParamDemo {
@Test
@Parameters({"name","age"})
public void test1(String name,int age){
System.out.println("name="+name+" age="+age);
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="mySuite3">
<test name="myTest3">
<classes>
<class name="com.dc.TestNGParamDemo">
<methods>
<include name="test1">
<parameter name="name" value="张三"></parameter>
<parameter name="age" value="18"></parameter>
</include>
</methods>
</class>
</classes>
</test>
</suite>
执行结果:
对象传参
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class TestNGParamDemo {
@Test(dataProvider = "user")
public void test1(String name,int age){
System.out.println("name="+name+" age="+age);
}
@DataProvider(name="user")
public Object[][] providerData(){
Object[][] user = new Object[][]{
{"张三",19},
{"李四",24},
{"王五",30}
};
return user;
}
}
执行结果:
方法映射传参
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.lang.reflect.Method;
public class TestNGParamDemo {
@Test(dataProvider = "methodData")
public void test2(String name,int age){
System.out.println("name="+name+" age="+age);
}
@Test(dataProvider = "methodData")
public void test3(String name,int age){
System.out.println("name="+name+" age="+age);
}
@DataProvider(name="methodData")
public Object[][] providerMethodData(Method method){
Object[][] result = null;
if (method.getName().equals("test2")){
result = new Object[][]{
{"张三", 19}
};
}else if (method.getName().equals("test3")){
result = new Object[][]{
{"李四",24}
};
}else {
result = new Object[][]{
{"王五",34}
};
}
return result;
}
}
执行结果:
超时测试
@Test(timeOut = 毫秒)
超过时间就报错
评论区