一.TestNG介绍
1.适合测试人员使用的原因
- 比Junit涵盖功能更全面的测试框架
- Junit更适合隔离性比较强的单元测试
- TestNG更适合复杂的集成测试
2.TestNG的使用
-
maven引入
<dependencies> <dependency> <groupId>org.testing</groupId> <artifactId>testing</artifactId> <version>release</version> </dependency> </dependencies>
3.TestNG基本注解与执行顺序实战
-
创建maven的工程文件
-
使用最基本的@Test注解,用来把方法标记为测试的一部分
package com.course.testng; import org.testng.annotations.Test; public class BasicAnnotation { //最基本的注解,用来把方法标记为测试的一部分 @Test public void testCase1() { System.out.println("这是测试用例1"); } }
-
注解实战@BeforeMethod和@AfterMethod
package com.course.testng; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class BasicAnnotation { //最基本的注解,用来把方法标记为测试的一部分 @Test public void testCase1() { System.out.println("这是测试用例1"); } //BeforeMethod是在测试方法之前运行的 @BeforeMethod public void beforeMethod(){ System.out.println("BeforeMethod是在测试方法之前运行的"); } //AfterMethod是在测试方法之后运行的 @AfterMethod public void afterMethod(){ System.out.println("AfterMethod是在测试方法之后运行的"); } } //运行结果 //BeforeMethod是在测试方法之前运行的 //这是测试用例1 //AfterMethod是在测试方法之后运行的
- 当在类中添加case方法时,运行类则可以发现每个Test方法的前后都有BeforeMethod和AfterMethod方法
package com.course.testng; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class BasicAnnotation { //最基本的注解,用来把方法标记为测试的一部分 @Test public void testCase1() { System.out.println("这是测试用例1"); } @Test public void testCase2() { System.out.println("这是测试用例2"); } //BeforeMethod是在测试方法之前运行的 @BeforeMethod public void beforeMethod(){ System.out.println("BeforeMethod是在测试方法之前运行的"); } //AfterMethod是在测试方法之后运行的 @AfterMethod public void afterMethod(){ System.out.println("AfterMethod是在测试方法之后运行的"); } } //运行类结果 //BeforeMethod是在测试方法之前运行的 //这是测试用例1 //AfterMethod是在测试方法之后运行的 //BeforeMethod是在测试方法之前运行的 //这是测试用例2 //AfterMethod是在测试方法之后运行的
-
注解实战@BeforeClass和@AfterClass,在类运行之前和之后执行的方法
package com.course.testng; import org.testng.annotations.*; public class BasicAnnotation { //最基本的注解,用来把方法标记为测试的一部分 @Test public void testCase1() { System.out.println("这是测试用例1"); } @Test public void testCase2() { System.out.println("这是测试用例2"); } //BeforeMethod是在测试方法之前运行的 @BeforeMethod public void beforeMethod(){ System.out.println("BeforeMethod是在测试方法之前运行的"); } //AfterMethod是在测试方法之后运行的 @AfterMethod public void afterMethod(){ System.out.println("AfterMethod是在测试方法之后运行的"); } //BeforeClass是在类运行之前运行的方法 @BeforeClass public void beforeClass(){ System.out.println("BeforeClass是在类运行之前运行的方法"); } //AfterClass是在类运行之后运行的方法 @AfterClass public void afterClass(){ System.out.println("AfterClass是在类运行之后运行的方法"); } } //运行结果 //BeforeClass是在类运行之前运行的方法 //BeforeMethod是在测试方法之前运行的 //这是测试用例1 //AfterMethod是在测试方法之后运行的 //BeforeMethod是在测试方法之前运行的 //这是测试用例2 //AfterMethod是在测试方法之后运行的 //AfterClass是在类运行之后运行的方法
-
注解实战BeforeSuite和AfterSuite测试套件,在类执行之前的前面运行和在类执行之后的后面执行
package com.course.testng; import org.testng.annotations.*; public class BasicAnnotation { //最基本的注解,用来把方法标记为测试的一部分 @Test public void testCase1() { System.out.println("这是测试用例1"); } @Test public void testCase2() { System.out.println("这是测试用例2"); } //BeforeMethod是在测试方法之前运行的 @BeforeMethod public void beforeMethod(){ System.out.println("BeforeMethod是在测试方法之前运行的"); } //AfterMethod是在测试方法之后运行的 @AfterMethod public void afterMethod(){ System.out.println("AfterMethod是在测试方法之后运行的"); } //BeforeClass是在类运行之前运行的方法 @BeforeClass public void beforeClass(){ System.out.println("BeforeClass是在类运行之前运行的方法"); } //AfterClass是在类运行之后运行的方法 @AfterClass public void afterClass(){ System.out.println("AfterClass是在类运行之后运行的方法"); } //beforeSuite在beforeClass之前执行 @BeforeSuite public void beforeSuite(){ System.out.println("beforeSuite测试套件"); } //afterSuite在afterClass之后执行 @AfterSuite public void afterSuite(){ System.out.println("afterSuite测试套件"); } } //运行结果 //beforeSuite测试套件 //BeforeClass是在类运行之前运行的方法 //BeforeMethod是在测试方法之前运行的 //这是测试用例1 //AfterMethod是在测试方法之后运行的 //BeforeMethod是在测试方法之前运行的 //这是测试用例2 //AfterMethod是在测试方法之后运行的 //AfterClass是在类运行之后运行的方法 //afterSuite测试套件
4.TestNG套件测试
-
编写
SuiteConfig.java
文件(文件名可以自定义,主要用于配置套件的相关方法编写)package com.course.testng.suite; import org.testng.annotations.AfterSuite; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeSuite; import org.testng.annotations.BeforeTest; public class SuiteConfig { @BeforeSuite public void beforeSuite(){ System.out.println("before suite运行啦"); } @AfterSuite public void afterSuite(){ System.out.println("after suite运行啦"); } @BeforeTest public void beforeTest(){ System.out.println("beforeTest"); } @AfterTest public void afterTest(){ System.out.println("afterTest"); } }
-
编写
LoginTest.java
文件和PayTest.java
文件(文件名可以自定义,主要编写固定的测试用例)//PayTest.java package com.course.testng.suite; import org.testng.annotations.Test; public class PayTest { @Test public void paySuccess(){ System.out.println("支付宝支付成功"); } } //LoginTest.java package com.course.testng.suite; import org.testng.annotations.Test; public class LoginTest { @Test public void loginTaoBao(){ System.out.println("淘宝登录成功"); } }
-
编写
suite.xml
文件(文件名可以自定义,主要用于将配置套件文件与用例文件整合)<?xml version="1.0" encoding="UTF-8" ?><!-- 标准xml文件头 --> <suite name="test"> <test name="login"> <classes> <class name="com.course.testng.suite.SuiteConfig"/> <class name="com.course.testng.suite.LoginTest"/> </classes> </test> <test name="pay"> <classes> <class name="com.course.testng.suite.SuiteConfig"/> <class name="com.course.testng.suite.PayTest"/> </classes> </test> </suite>
-
执行
suite.xml
文件before suite运行啦 beforeTest 淘宝登录成功 afterTest beforeTest 支付宝支付成功 afterTest after suite运行啦
5.TestNG忽略测试
-
创建文件
IgnoreTest.java
文件 -
忽略测试:指的是当前不执行某个测试用例,将@Test的enabled属性设置为false即可(默认enabled属性值为true)
package com.course.testng; import org.testng.annotations.Test; public class IgnoreTest { @Test public void ignore1(){ System.out.println("ignore1 执行!"); } @Test(enabled = false) public void ignore2(){ System.out.println("ignore2 执行!"); } @Test(enabled = true) public void ignore3(){ System.out.println("ignore3 执行!"); } } //执行结果 //ignore1 执行! //ignore3 执行!
二.TestNG组测试
1.组测试中的方法分组测试
-
创建
GroupsOnMethod.java
文件 -
方法分组测试:利用@BeforeGroups和@AfterGroups筛选在对应groups的前后执行的内容
-
实例代码
package com.course.testng.groups; import org.testng.annotations.AfterGroups; import org.testng.annotations.BeforeGroups; import org.testng.annotations.Test; public class GroupsOnMethod { @Test(groups = "server") public void test1(){ System.out.println("这是服务端组的测试方法11111"); } @Test(groups = "server") public void test2(){ System.out.println("这是服务端组的测试方法22222"); } @Test(groups = "client") public void test3(){ System.out.println("这是客户端组的测试方法33333"); } @Test(groups = "client") public void test4(){ System.out.println("这是客户端组的测试方法44444"); } @BeforeGroups("server") public void beforeGroupsOnServer(){ System.out.println("这是服务端组运行之前运行的方法"); } @AfterGroups("server") public void afterGroupsOnServer(){ System.out.println("这是服务端组运行之后运行的方法"); } @BeforeGroups("client") public void beforeGroupsOnClient(){ System.out.println("这是客户端组运行之前运行的方法"); } @AfterGroups("client") public void afterGroupsOnClient(){ System.out.println("这是客户端组运行之后运行的方法"); } } //运行结果 //这是服务端组运行之前运行的方法 //这是服务端组的测试方法11111 //这是服务端组的测试方法22222 //这是服务端组运行之后运行的方法 //这是客户端组运行之前运行的方法 //这是客户端组的测试方法33333 //这是客户端组的测试方法44444 //这是客户端组运行之后运行的方法
2.组测试中的类分组测试
-
创建
GroupsOnClass1.java
文件package com.course.testng.groups; import org.testng.annotations.Test; @Test(groups = "stu")//给类命名groups public class GroupsOnClass1 { public void stu1(){ System.out.println("GroupsOnClass1中的stu1运行"); } public void stu2(){ System.out.println("GroupsOnClass1中的stu2运行"); } }
-
创建
GroupsOnClass2.java
文件package com.course.testng.groups; import org.testng.annotations.Test; @Test(groups = "stu")//给类命名groups public class GroupsOnClass2 { public void stu1(){ System.out.println("GroupsOnClass2中的stu1运行"); } public void stu2(){ System.out.println("GroupsOnClass2中的stu2运行"); } }
-
创建
GroupsOnClass3.java
文件package com.course.testng.groups; import org.testng.annotations.Test; @Test(groups = "teacher")//给类命名groups public class GroupsOnClass3 { public void teacher1(){ System.out.println("GroupsOnClass3中的teacher1运行"); } public void teacher2(){ System.out.println("GroupsOnClass3中的teacher2运行"); } }
-
创建
groupsOnClass.xml
文件<?xml version="1.0" encoding="UTF-8" ?> <suite name="suitename"> <test name="runAll"><!-- 运行所有的组 --> <classes> <class name="com.course.testng.groups.GroupsOnClass1"/> <class name="com.course.testng.groups.GroupsOnClass2"/> <class name="com.course.testng.groups.GroupsOnClass3"/> </classes> </test> <test name="onlyRunStu"> <groups> <run> <include name="stu"/><!-- 只运行groups为stu的类组的方法 --> </run> </groups> <classes> <class name="com.course.testng.groups.GroupsOnClass1"/> <class name="com.course.testng.groups.GroupsOnClass2"/> <class name="com.course.testng.groups.GroupsOnClass3"/> </classes> </test> </suite>
-
利用阻塞式配置
groups->run->include
,设置执行哪组的类 -
执行xml结果(前六条因为没有指定设置则执行所有的组,后四条因为利用阻塞式配置只运行groups为stu的组中的类的方法)
GroupsOnClass1中的stu1运行 GroupsOnClass1中的stu2运行 GroupsOnClass2中的stu1运行 GroupsOnClass2中的stu2运行 GroupsOnClass3中的teacher1运行 GroupsOnClass3中的teacher2运行 GroupsOnClass1中的stu1运行 GroupsOnClass1中的stu2运行 GroupsOnClass2中的stu1运行 GroupsOnClass2中的stu2运行
-
三.TestNG异常测试
1.什么时候使用异常测试
-
在我们期望结果为某一个异常的时候(系统抛出的异常或显式抛出的异常)
-
比如:我们传入了某些不合法的参数,程序抛出异常
-
也就是我的预期结果就是这个异常
2.异常测试举例
-
失败的异常测试(下述代码因为没有异常,所以异常测试失败)
//这是一个测试结果会失败的异常测试 @Test(expectedExceptions = RuntimeException.class) public void runTimeExceptionFailed(){ System.out.println("这是一个失败的异常测试"); }
-
成功的异常测试(下述代码因为有异常,所以异常测试成功)
//这是一个成功的异常测试 @Test(expectedExceptions = RuntimeException.class) public void runTimeExceptionSuccess(){ System.out.println("这是我的异常测试"); throw new RuntimeException(); }
四.TestNG依赖测试
-
依赖测试:本测试方法依赖于其他的方法,使用@Test中的
dependsOnMethods = {"其他方法名"}
属性进行控制 -
实例代码
package com.course.testng; import org.testng.annotations.Test; public class DependTest { @Test public void test1(){ System.out.println("test1 run"); } @Test(dependsOnMethods = {"test1"})//将test1作为test2的前置条件 public void test2(){ System.out.println("test2 run"); } @Test public void test3(){ System.out.println("test3 run"); throw new RuntimeException(); } @Test(dependsOnMethods = {"test3"})//将test3作为test4的前置条件,test3失败则test4被忽略 public void test4(){ System.out.println("test4 run"); } } //运行test2的结果为(因为依赖的test1没有异常) //test1 run //test2 run //运行test4的结果为(因为依赖的test3抛出异常) //java.lang.RuntimeException // ... //Test ignored.
五.TestNG参数化测试
1.xml文件参数化测试
-
xml文件参数化测试:给对应方法中传递参数进行测试,在类中使用@Parameters注解定义要传的参数名称,在xml的配置文件中使用
<parameter>
标签的name和value设置传递的具体参数值 -
实例代码
-
ParamterTest.java
文件package com.course.testng.paramter; import org.testng.annotations.Parameters; import org.testng.annotations.Test; public class ParamterTest { @Test @Parameters({"name","age"}) public void paramterTest1(String name, int age){ System.out.println("name="+name+" age="+age); } }
-
parameter.xml
文件<?xml version="1.0" encoding="UTF-8" ?> <suite name="parameter"> <test name="param"> <classes> <parameter name="name" value="zhangsan"/> <parameter name="age" value="10"/> <class name="com.course.testng.paramter.ParamterTest"></class> </classes> </test> </suite>
-
执行xml的运行结果
name=zhangsan age=10
-
2.DataProvider参数化测试
-
将需要执行的测试方法@Test的dataProvider属性值与@DataProvider定义的方法的name属性值设置相同,@DataProvider方法主要用于提供参数对象。实例代码如下
package com.course.testng.paramter; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.lang.reflect.Method; public class DataProviderTest { @Test(dataProvider = "data") public void testDataProvider(String name, int age){ System.out.println("name="+name+" age="+age); //运行结果 //name=张三 age=10 //name=李四 age=20 //name=王五 age=30 } @DataProvider(name="data")//name与需要使用的方法Test注解的dataProvider属性值相同 public Object[][] providerData(){ Object [][] o= new Object[][]{//相当于给参数传递三次参数,分别执行三次测试方法 {"张三",10}, {"李四",20}, {"王五",30} }; return o; } }
-
当一个@DataProvider方法修饰多个测试方法时,通过@DataProvider修饰方法的Method参数判断给对应测试方法的方法名设置对应传递给测试方法的参数内容
package com.course.testng.paramter; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.lang.reflect.Method; public class DataProviderTest { @Test(dataProvider = "methodData") public void test1(String name, int age){ System.out.println("test1方法:name="+name+" age="+age); //运行结果 //test1方法:name=张三 age=15 //test1方法:name=李四 age=25 } @Test(dataProvider = "methodData") public void test2(String name, int age){ System.out.println("test2方法:name="+name+" age="+age); //运行结果 //test2方法:name=王五 age=50 //test2方法:name=赵六 age=60 } @DataProvider(name = "methodData") public Object[][] methodData(Method method){//method表示测试的方法名 Object[][] result=null; if(method.getName().equals("test1")){ result = new Object[][]{ {"张三",15}, {"李四",25} }; }else if(method.getName().equals("test2")){ result = new Object[][]{ {"王五",50}, {"赵六",60} }; } return result; } }
六.TestNG多线程测试
1.java注解实现多线程测试
-
使用@Test的invocationCount设置方法的执行次数
-
使用@Test的threadPoolSize设置线程池内的线程个数
-
实例代码
package com.course.testng.multiThread; import org.testng.annotations.Test; public class MultiThreadOnAnnotation { @Test(invocationCount = 10, threadPoolSize = 3) public void test(){ System.out.println(1); System.out.printf("Thread ID:%s %n",Thread.currentThread()); } } //运行结果——通过Thread.currentThread()得到当前所处的线程信息 //1 //1 //Thread ID:Thread[TestNG-methods-1,5,main] //1 //Thread ID:Thread[TestNG-methods-2,5,main] //Thread ID:Thread[TestNG-methods-3,5,main] //1 //Thread ID:Thread[TestNG-methods-3,5,main] //1 //Thread ID:Thread[TestNG-methods-2,5,main] //1 //Thread ID:Thread[TestNG-methods-1,5,main] //1 //Thread ID:Thread[TestNG-methods-1,5,main] //1 //Thread ID:Thread[TestNG-methods-3,5,main] //1 //Thread ID:Thread[TestNG-methods-2,5,main] //1 //Thread ID:Thread[TestNG-methods-1,5,main]
2.xml文件实现多线程测试
-
使用xml中suite的parallel属性决定多线程级别,thread-count属性决定最大并发线程数
-
parallel属性值
- tests级别:不同的test tag下的用例可以在不同的线程下执行,相同的test tag下的用例只能在同一个线程中取执行
- classs级别:相同的class tag下的用例在同一个线程下执行,不同的class tag下的用例可以在不同的线程下执行
- methods级别:所有用例都可以在不同的线程下去执行
-
xml文件配置这种方式不能指定线程池,只有方法上才可以指定线程池
-
实例代码
-
MultiThreadOnXml.java
文件代码package com.course.testng.multiThread; import org.testng.annotations.Test; public class MultiThreadOnXml { @Test(invocationCount = 3) public void test1(){ System.out.printf("Thread ID:%s %n",Thread.currentThread().getId());//打印线程ID } }
-
multiThread.xml
文件代码<?xml version="1.0" encoding="UTF-8" ?> <suite name="thread" parallel="methods" thread-count="2"><!-- parallel表示多线程级别是方法级别的,thread-count表示的是线程数是2 --> <!-- tests级别:不同的test tag下的用例可以在不同的线程下执行,相同的test tag下的用例只能在同一个线程中取执行 classs级别:相同的class tag下的用例在同一个线程下执行,不同的class tag下的用例可以在不同的线程下执行 methods级别:所有用例都可以在不同的线程下去执行 thread-count:代表了最大并发线程数 xml文件配置这种方式不能指定线程池,只有方法上才可以指定线程池 --> <test name="demo1"> <classes> <class name="com.course.testng.multiThread.MultiThreadOnXml"/> </classes> </test> <test name="demo2"> <classes> <class name="com.course.testng.multiThread.MultiThreadOnXml"/> </classes> </test> </suite>
-
七.TestNG超时测试
-
通过设置@Test的timeout属性值进行超时测试,timeout属性值单位为毫秒值
-
实例代码
package com.course.testng; import org.testng.annotations.Test; public class TimeOutTest { @Test(timeOut = 3000)//单位为毫秒值 public void testSuccess() throws InterruptedException {//测试通过 Thread.sleep(2000); } @Test(timeOut = 2000)//单位为毫秒值 public void testFailed() throws InterruptedException {//测试失败 Thread.sleep(3000); } }