TestNG操作详解
一、 TestNG使用流程
1.1TestNG安装
本文以IDEA+Maven为例介绍TestNG,IntelliJ IDEA版本为IntelliJ IDEA。
IntelliJ IDEA中默认集成了TestNG,点击File->Settings,如下图:
1.2 创建Maven项目
点击File->new-Project,如图
创建基于Maven的项目
创建名字为MavenTest的项目,创建完成后如下图
1.3 Maven配置
在工程的pom.xml中需要添加如下依赖:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<?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>org.example</groupId> <artifactId>MavenTest</artifactId> <version> 1.0 -SNAPSHOT</version> <dependencies> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version> 6.10 </version> </dependency> </dependencies> </project> |
1.4 项目TestNG测试类
点击类名Test,按alt+entet键,创建单元测试类
点击Create Test
OK,生成测试类
1.5 运行TestNG
运行结果:
二、TestNG常用注解
TestNG常用注解:
注解 | 描述 |
@BeforeSuite | 被注释的方法将在所有测试运行前运行(相当于前置条件) |
@AfterSuite |
被注释的方法将在所有测试运行后运行比如关闭浏览器(使执行其他用例时处于初始状态) |
@BeforeTest | 被注释的方法将在测试运行前运行 |
@AfterTest | 被注释的方法将在测试运行后运行 |
@BeforeGroups |
被配置的方法将在列表中的gourp前运行。这个方法保证在第一个属于这些组的测试方法调用 前立即执行 |
@AfterGroups |
被配置的方法将在列表中的gourp后运行。这个方法保证在最后一个属于这些组的测试方法调 用后立即执行 |
@BeforeClass | 被注释的方法将在当前类的第一个测试方法调用前运行 |
@AfterClass | 被注释的方法将在当前类的所有测试方法调用后运行 |
@BeforeMethod | 被注释的方法将在每一个测试方法调用前运行 |
@AfterMethod | 被注释的方法将在每一个测试方法调用后运行 |
@DataProvider |
标记一个方法用于为测试方法提供数据。 被注释的方法必须返回Object[][],其中每个Object[] 可以指派为这个测试方法的参数列表。从这个DataProvider接收数@Test方法需要使用一个和 当前注释相同名称的dataProvider名称 |
@Factory |
标记方法作为一个返回对象的工厂, 这些对象将被TestNG用于作为测试类。这个方法必须返回 Object[] |
@Listeners | 定义一个测试类的监听器 |
@Parameters | 描述如何传递参数给@Test方法 |
@Test | 标记一个类或方法作为测试的一部分 |
备注:
1
2
3
4
5
|
Before开头的注解一般用于初始化环境、 准备测试环境 after开头的注解一般用于执行测试的环境清理工作 DataProvider一般用作参数化用的, 属于数据驱动自动化(即不同的测试数据测试相同的测试逻辑) Listeners 自定义日志或者监控一些testNG用例执行成功或者失败的时候做些特别的事情 Parameters可以把xml文件定义的参数传递到测试程序或者测试类中来使用 |
案例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
public class yihuqingjiu_test_demo { @Test public void testCase1() { System.out.println( "in test case 1" ); } @Test public void testCase2() { System.out.println( "in test case 2" ); } @BeforeMethod public void beforeMethod() { System.out.println( "in beforeMethod" ); } @AfterMethod public void afterMethod() { System.out.println( "in afterMethod" ); } @BeforeClass public void beforeClass() { System.out.println( "in beforeClass" ); } @AfterClass public void afterClass() { System.out.println( "in afterClass" ); } @BeforeTest public void beforeTest() { System.out.println( "in beforeTest" ); } @AfterTest public void afterTest() { System.out.println( "in afterTest" ); } @BeforeSuite public void beforeSuite() { System.out.println( "in beforeSuite" ); } @AfterSuite public void afterSuite() { System.out.println( "in afterSuite" ); } } |
运行结果:
in beforeSuite
in beforeTest
in beforeClass
in beforeMethod
in test case 1
in afterMethod
in beforeMethod
in test case 2
in afterMethod
in afterClass
in afterTest
1
2
3
4
5
6
|
TestNG的执行过程如下: 首先beforeSuite()方法执行一次。 最后afterSuite的()方法执行一次。 其次方法 beforeTest(), beforeClass(), afterClass() 和afterTest() 方法各执行一次。 beforeMethod()方法在执行每个测试用例之前执行一次。 afterMethod()方法在执行每个测试用例之后执行一次。 |
三、TestNG常用断言
1
2
3
4
5
6
7
8
|
assertEqual ([String message], expected value, actual value) 断言两个值相等。值可能是类型有 int , short , long , byte , char or java.lang.Object. 第一个参数是一个可选的字符串消息; assertTrue([String message], boolean condition) 断言一个条件为真; assertFalse([String message], boolean condition) 断言一个条件为假; assertNotNull([String message], java.lang.Object object) 断言一个对象不为空( null ); assertNull([String message], java.lang.Object object) 断言一个对象为空( null ); assertSame([String message], java.lang.Object expected, java.lang.Object actual) 断言两个对象引用相同的对象; assertNotSame([String message], java.lang.Object unexpected, java.lang.Object actual) 断言两个对象不是引用同一个对象; assertArrayEquals([String message], expectedArray, resultArray) 断言预期数组和结果数组相等。数组的类型可能是 int , long , short , char , byte or java.lang.Object.; |
四、使用maven运行
需要在pom文件中,指明testng.xml文件的位置。
maven使用surefire这个插件进行测试,可以执行testng或者Junit脚本。
语法为 <suiteXmlFile>src/test/resources/testNGFilesFolder/${testNgFileName}.xml</suiteXmlFile>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version> 2.8 </version> </dependency> </dependencies> <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><em id= "__mceDel" style= " font-family: "PingFang SC", "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 14px" > </em> |
五、TestNG忽略测试
通过注解@Test(enabled = false)
来将其忽略掉,此用例就不会运行了,如下范例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import org.testng.annotations.Test; public class TestCase1 { @Test (enabled= false ) public void TestNgLearn1() { System.out.println( "this is TestNG test case1" ); } @Test public void TestNgLearn2() { System.out.println( "this is TestNG test case2" ); } } |
运行结果:
1
2
|
this is TestNG test case2 PASSED: TestNgLearn2 |
六、TestNG超时测试
超时”表示如果单元测试花费的时间超过指定的毫秒数,那么TestNG将会中止它并将其标记为失败。如下为一个范例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
import org.testng.annotations.Test; public class TestCase1 { @Test (timeOut = 5000 ) // time in mulliseconds public void testThisShouldPass() throws InterruptedException { Thread.sleep( 4000 ); } @Test (timeOut = 1000 ) public void testThisShouldFail() { while ( true ){ // do nothing } } } |
结果如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
PASSED: testThisShouldPass FAILED: testThisShouldFail org.testng.internal.thread.ThreadTimeoutException: Method com.demo.test.testng.TestCase1.testThisShouldFail() didn't finish within the time-out 1000 at com.demo.test.testng.TestCase1.testThisShouldFail(TestCase1.java: 37 ) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java: 62 ) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java: 43 ) at java.lang.reflect.Method.invoke(Method.java: 498 ) at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java: 104 ) at org.testng.internal.InvokeMethodRunnable.runOne(InvokeMethodRunnable.java: 54 ) at org.testng.internal.InvokeMethodRunnable.run(InvokeMethodRunnable.java: 44 ) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java: 511 ) at java.util.concurrent.FutureTask.run(FutureTask.java: 266 ) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java: 1149 ) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java: 624 ) at java.lang.Thread.run(Thread.java: 748 ) |
七、分组测试
顾名思义,是将不同的用例分组,然后再testng.xml文件中配置信息,而执行相应组的用例,代码实现如下,仅供参考:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
package com.ui.day4; import org.testng.Assert; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; public class yihuqingjiu_test_group { ca a; @BeforeSuite (groups = { "冒烟" , "回归" }) public void reday() { a = new ca(); } @Test (groups = "冒烟" ) public void add() { Assert.assertEquals(a.add( 5 , 6 ), 11 ); } @Test (groups = "冒烟" ) public void min() { Assert.assertEquals(a.minus( 6 , 5 ), 1 ); } @Test (groups = "冒烟" ) public void cheng() { Assert.assertEquals(a.cheng( 6 , 5 ), 30 ); } @Test (groups = "回归" ) public void cheng1() { Assert.assertEquals(a.cheng( 6 , 5 ), 30 ); } @Test (groups = "回归" ) public void chu() { Assert.assertEquals(a.chu( 5 , 5 ), 1 ); } } |
testng.xml文件配置如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<?xml version= "1.0" encoding= "UTF-8" ?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name= "Suite1" verbose= "3" > <test name= "test_one" > <groups> <run> <include name= "回归" /> </run> </groups> <classes> < class name= "com.ui.day4.test_group" ></ class > </classes> </test> </suite> |
八、suite套件测试
测试套件是用于测试软件程序的行为或一组行为的测试用例的集合。 在TestNG中,我们无法在测试源代码中定义一个套件,但它可以由一个XML文件表示,因为套件是执行的功能。 它还允许灵活配置要运行的测试。 套件可以包含一个或多个测试,并由<suite>标记定义。<suite>是testng.xml的根标记。 它描述了一个测试套件,它又由几个<test>部分组成。
下表列出了<suite>接受的所有定义的合法属性。
suite常用属性介绍 | |
注解 | 描述 |
@name | suite的名称, 必须参数 |
@verbose | 命令行信息打印等级, 不会影响测试报告输出内容; 可选值(1|2|3|4|5) |
@parallel |
是否多线程并发运行测试; 可选值(false | methods | tests | classes |instances)默认 "false" |
@thread-count | 当为并发执行时的线程池数量, 默认为"5" |
@annotations | 获取注解的位置, 如果为"javadoc", 则使用javadoc注解, 否则使用jdk注解 |
junit | 是否以Junit模式运行, 可选值(true | false), 默认"false" |
@time-out | 为具体执行单元设定一个超时时间, 具体参照parallel的执行单元设置; 单位为毫秒 |
九、自定义执行顺序测试
按照一定的顺序去执行测试方法, 通过priority属性去设 置,如下代码实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public class yihuqingjiu_demo { @Test (priority= 2 ) public void print3(){ System.out.println( "壶" ); } @Test (priority= 0 ) public void print1(){ System.out.println( "温" ); } @Test (priority= 1 ) public void print2(){ System.out.println( "一" ); } @Test (priority= 4 ) public void print5(){ System.out.println( "酒" ); } @Test (priority= 3 ) public void print4(){ System.out.println( "清" ); } } |
执行顺序为print1--->print2--->print3--->print4--->print5
属性值为0代表最高优先级
还可以在testng.xml文件中设置,设置如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<?xml version= "1.0" encoding= "UTF-8" ?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name= "Suite1" > <test name= "test" preserve-order= "true" > <classes> < class name= "com.ui.day4.test_demo" > <methods> <include name= "print5" /> <include name= "print2" /> <include name= "print4" /> <include name= "print1" /> <include name= "print3" /> </methods> </ class > </classes> </test> </suite> |
preserve-order属性设置为true
依据include配置的顺序执行测试方法
十、依赖测试
有时,我们可能需要以特定顺序调用测试用例中的方法,或者可能希望在方法之间共享一些数据和状态。 TestNG支持这种依赖关系,因为它支持在测试方法之间显式依赖的声明。
TestNG允许指定依赖关系:
在@Test注释中使用属性dependsOnMethods
在@Test注释中使用属性dependsOnGroups
在TestNG中,我们使用dependOnMethods和dependsOnGroups来实现依赖测试。 且这两个都支持正则表达式,如范例三所示,如下为几个使用范例:
案例1:被依赖方法pass:
1
2
3
4
5
6
7
8
9
10
11
12
|
public class TestCase1 { @Test (enabled= true ) public void TestNgLearn1() { System.out.println( "this is TestNG test case1" ); } @Test (dependsOnMethods= { "TestNgLearn1" }) public void TestNgLearn2() { System.out.println( "this is TestNG test case2" ); } } |
运行结果:
1
2
3
4
|
this is TestNG test case1 this is TestNG test case2 PASSED: TestNgLearn1 PASSED: TestNgLearn2 |
案例2: 被依赖方法fail:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public class TestCase1 { @Test (enabled= true ) public void TestNgLearn1() { System.out.println( "this is TestNG test case1" ); Assert.assertFalse( true ); } @Test (dependsOnMethods= { "TestNgLearn1" }) public void TestNgLearn2() { System.out.println( "this is TestNG test case2" ); } } |
运行结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
this is TestNG test case1 FAILED: TestNgLearn1 junit.framework.AssertionFailedError at junit.framework.Assert.fail(Assert.java: 47 ) at junit.framework.Assert.assertTrue(Assert.java: 20 ) at junit.framework.Assert.assertFalse(Assert.java: 34 ) at junit.framework.Assert.assertFalse(Assert.java: 41 ) at com.demo.test.testng.TestCase1.TestNgLearn1(TestCase1.java: 26 ) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java: 62 ) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java: 43 ) at java.lang.reflect.Method.invoke(Method.java: 498 ) at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java: 104 ) at org.testng.internal.Invoker.invokeMethod(Invoker.java: 645 ) at org.testng.internal.Invoker.invokeTestMethod(Invoker.java: 851 ) at org.testng.internal.Invoker.invokeTestMethods(Invoker.java: 1177 ) at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java: 129 ) at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java: 112 ) at org.testng.TestRunner.privateRun(TestRunner.java: 756 ) at org.testng.TestRunner.run(TestRunner.java: 610 ) at org.testng.SuiteRunner.runTest(SuiteRunner.java: 387 ) at org.testng.SuiteRunner.runSequentially(SuiteRunner.java: 382 ) at org.testng.SuiteRunner.privateRun(SuiteRunner.java: 340 ) at org.testng.SuiteRunner.run(SuiteRunner.java: 289 ) at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java: 52 ) at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java: 86 ) at org.testng.TestNG.runSuitesSequentially(TestNG.java: 1293 ) at org.testng.TestNG.runSuitesLocally(TestNG.java: 1218 ) at org.testng.TestNG.runSuites(TestNG.java: 1133 ) at org.testng.TestNG.run(TestNG.java: 1104 ) at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java: 114 ) at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java: 251 ) at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java: 77 ) SKIPPED: TestNgLearn2 |
十一、参数化测试
TestNG可以通过两种不同的方式将参数直接传递给测试方法:
下面分别介绍两种传参方式
1、使用textng.xml传送参数
范例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class TestCase1 { @Test (enabled= true ) @Parameters ({ "param1" , "param2" }) public void TestNgLearn1(String param1, int param2) { System.out.println( "this is TestNG test case1, and param1 is:" +param1+ "; param2 is:" +param2); Assert.assertFalse( false ); } @Test (dependsOnMethods= { "TestNgLearn1" }) public void TestNgLearn2() { System.out.println( "this is TestNG test case2" ); } } |
xml配置:
1
2
3
4
5
6
7
8
9
10
|
<?xml version= "1.0" encoding= "UTF-8" ?> <suite name= "Suite" parallel= "false" > <test name= "Test" > <parameter name= "param1" value= "1011111" /> <parameter name= "param2" value= "10" /> <classes> < class name= "com.demo.test.testng.TestCase1" /> </classes> </test> <!-- Test --> </suite> <!-- Suite --> |
运行xml,结果如下:
1
2
3
4
5
6
7
|
this is TestNG test case1, and param1 is: 1011111 ; param2 is: 10 this is TestNG test case2 =============================================== Suite Total tests run: 2 , Failures: 0 , Skips: 0 =============================================== |
2、使用@DataProvider传递参数
此处需要注意,传参的类型必须要一致,且带有@DataProvider注解的函数返回的必然是Object[][],此处需要注意。
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public class TestCase1 { @DataProvider (name = "provideNumbers" ) public Object[][] provideData() { return new Object[][] { { 10 , 20 }, { 100 , 110 }, { 200 , 210 } }; } @Test (dataProvider = "provideNumbers" ) public void TestNgLearn1( int param1, int param2) { System.out.println( "this is TestNG test case1, and param1 is:" +param1+ "; param2 is:" +param2); Assert.assertFalse( false ); } @Test (dependsOnMethods= { "TestNgLearn1" }) public void TestNgLearn2() { System.out.println( "this is TestNG test case2" ); } } |
运行此class,结果为:
1
2
3
4
5
6
7
8
|
this is TestNG test case1, and param1 is: 10 ; param2 is: 20 this is TestNG test case1, and param1 is: 100 ; param2 is: 110 this is TestNG test case1, and param1 is: 200 ; param2 is: 210 this is TestNG test case2 PASSED: TestNgLearn1( 10 , 20 ) PASSED: TestNgLearn1( 100 , 110 ) PASSED: TestNgLearn1( 200 , 210 ) PASSED: TestNgLearn2 |
本文作者:云龙
本文链接:https://www.cnblogs.com/yunlong-study/p/18281239
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步