Java盲点攻克「TestNG专题」摒弃JUnit单元测试,带你学会使用TestNG测试框架(上篇)
Posted 洛神灬殇
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java盲点攻克「TestNG专题」摒弃JUnit单元测试,带你学会使用TestNG测试框架(上篇)相关的知识,希望对你有一定的参考价值。
单元测试框架之TestNG使用教程指南(上篇)
TestNG介绍
TestNG是Java中的一个测试框架, 类似于JUnit 和NUnit, 功能都差不多, 只是功能更加强大,使用也更方便。
详细使用说明请参考官方链接:https://testng.org/doc/index.html
TestNG安装
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.10</version>
<scope>test</scope>
</dependency>
TestNG的优点
- 漂亮的html格式测试报告
- 支持并发测试
- 参数化测试更简单
- 支持输出日志
- 支持更多功能的注解
编写TestNG测试用例的步骤
-
使用 Eclipse生成TestNG的测试程序框架
-
在生成的程序框架中编写测试代码逻辑
-
根据测试代码逻辑,插入TestNG注解标签
-
配置Testng.xml文件,设定测试类、测试方法、测试分组的执行信息
-
执行TestNG的测试程序
TestNG的简单用例
Java直接运行
package com.demo.test.testng;
import org.testng.annotations.Test;
public class NewTest
@Test
public void testFunction()
System.out.println("this is new test");
Assert.assertTrue(true);
xml方式运行
由于我将xml放置在其他文件夹,不和class放在一个文件夹,所以需要修改xml,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<suite name="Suite" parallel="false">
<test name="Test">
<classes>
<class name="com.demo.test.testng.NewTest"/>
</classes>
</test> <!-- Test -->
</suite> <!-- Suite -->
TestNG的注解
TestNG支持多种注解,可以进行各种组合,如下进行简单的说明
@BeforeSuite > @BeforeTest > @BeforeMethod > @Test > @AfterMethod > @AfterTest > @AfterSuite
如上列表中的@Factory、@Linsteners这两个是不常用的;
前十个注解看起来不太容易区分,顺序不太容易看明白,以如下范例做简单说明,代码
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterGroups;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
public class NewTest
@Test(groups="group1")
public void test1()
System.out.println("test1 from group1");
Assert.assertTrue(true);
@Test(groups="group1")
public void test11()
System.out.println("test11 from group1");
Assert.assertTrue(true);
@Test(groups="group2")
public void test2()
System.out.println("test2 from group2");
Assert.assertTrue(true);
@BeforeTest
public void beforeTest()
System.out.println("beforeTest");
@AfterTest
public void afterTest()
System.out.println("afterTest");
@BeforeClass
public void beforeClass()
System.out.println("beforeClass");
@AfterClass
public void afterClass()
System.out.println("afterClass");
@BeforeSuite
public void beforeSuite()
System.out.println("beforeSuite");
@AfterSuite
public void afterSuite()
System.out.println("afterSuite");
//只对group1有效,即test1和test11
@BeforeGroups(groups="group1")
public void beforeGroups()
System.out.println("beforeGroups");
//只对group1有效,即test1和test11
@AfterGroups(groups="group1")
public void afterGroups()
System.out.println("afterGroups");
@BeforeMethod
public void beforeMethod()
System.out.println("beforeMethod");
@AfterMethod
public void afterMethod()
System.out.println("afterMethod");
运行结果如下:
beforeSuite
beforeTest
beforeClass
beforeGroups
beforeMethod
test1 from group1
afterMethod
beforeMethod
test11 from group1
afterMethod
afterGroups
beforeMethod
test2 from group2
afterMethod
afterClass
afterTest
PASSED: test1
PASSED: test11
PASSED: test2
===============================================
Default test
Tests run: 3, Failures: 0, Skips: 0
===============================================
afterSuite
如何创建TestNG测试集合?
- 在自动化测试的执行过程中,通常会产生批量运行多个测试用例的需求,此需求称为运行测试集合(Test Suite)
- TestNG的测试用例可以是相互独立的,也可以按照特定的顺序来执行(配置TestNG.xml)
如何配置testNG.xml文件?
<suite name = "TestNG Suite"> //自定义的测试集合名称
<test name = "test1"> //自定义的测试名称
<classes> //定义被运行的测试类
<class name = "cn.gloryroad.FirstTestNGDemo" /> //测试类的路径
<class name = "cn.gloryroad.NewTest" />
</classes>
</test>
</suite>
测试用例的分组(group)
执行组分组配置如下:
<suite name = "TestNG Suite">
<test name = "Grouping">
<groups>
<run>
<include name = "动物" />
</run>
</groups>
<classes>
<class name = "cn.gloryroad.Grouping"/>
</classes>
</test>
</suite>
执行多组分组时配置如下(两种形式都可以):
<suite name = "TestNG Suite">
<test name = "Grouping">
<groups>
<run>
<include name = "动物" /> //name分组名称
<include name = "人" />
</run>
</groups>
<classes>
<class name = "cn.gloryroad.Grouping"/>
</classes>
</test>
</suite>
依赖测试(dependsOnMethod)
被依赖的方法优先于此方法执行
@Test(dependsOnMethod = "方法名称")
特定顺序执行测试用例(priority)
按照数字大小顺序优先执行,优先执行1,然后是2…
@Test(priority = 0/1/2/3/4/…)
如何跳过某个测试方法(enabled = false)
@Test(priority = 0/1… , enabled = false)
执行结束后,在测试报告中显示跳过的测试用例数,例如skip=1
创建测试案例类
- 创建一个Java测试类 ParameterizedTest1.java.
- 测试方法parameterTest()添加到测试类。此方法需要一个字符串作为输入参数。
- 添加注释 @Parameters(“myName”) 到此方法。该参数将被传递testng.xml,在下一步我们将看到一个值。
创建Java类文件名 ParameterizedTest1.java
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
public class ParameterizedTest1
@Test
@Parameters("myName")
public void parameterTest(String myName)
System.out.println("Parameterized value is : " + myName);
创建 TESTNG.XML
创建 testng.xml C:\\ > TestNG_WORKSPACE 执行测试案例
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite1">
<test name="test1">
<parameter name="myName" value="manisha"/>
<classes>
<class name="ParameterizedTest1" />
</classes>
</test>
</suite>
我们还可以定义参数在级别。假设我们已经定义在两个和级别myName,在这种情况下,常规的作用域规则适用。这意味着,任何类里面标签将查看值参数定义在,而testng.xml文件中的类的其余部分将看到定义在中值
编译使用javac的测试用例类。
javac ParameterizedTest1.java
现在,运行testng.xml,其中将运行parameterTest方法。TestNG的将试图找到一个命名myName的第一标签的参数,然后,如果它不能找到它,它会搜索包围在的标签。
验证输出。
Parameterized value is : manisha
===============================================
Suite1
Total tests run: 1, Failures: 0, Skips: 0
===============================================
数据驱动(@DataProvider)
-
当你需要通过复杂的参数或参数需要创建从Java(复杂的对象,对象读取属性文件或数据库等…),在这种情况下,可以将参数传递使用数据提供者。数据提供者@DataProvider的批注的方法。
-
这个注解只有一个字符串属性:它的名字。如果不提供名称,数据提供者的名称会自动默认方法的名称。数据提供者返回一个对象数组。
让我们看看下面的例子使用数据提供者。第一个例子是@DataProvider的使用Vector,String或Integer 作为参数,第二个例子是关于@DataProvider 的使用对象作为参数。
实例 1
在这里 @DataProvider 通过整数和布尔参数。
创建Java类
创建一个java类PrimeNumberChecker.java。这个类检查,如果是素数。
public class PrimeNumberChecker
public Boolean validate(final Integer primeNumber)
for (int i = 2; i < (primeNumber / 2); i++)
if (primeNumber % i == 0)
return false;
return true;
创建测试案例类
- 创建一个Java测试类 ParamTestWithDataProvider1.java.
- 定义方法primeNumbers(),其定义为DataProvider 使用注释。此方法返回的对象数组的数组。
- 测试方法testPrimeNumberChecker()添加到测试类中。此方法需要一个整数和布尔值作为输入参数。这个方法验证,如果传递的参数是一个素数。
- 添加注释 @Test(dataProvider = “test1”) 到此方法。dataProvider的属性被映射到"test1".
创建Java类文件名ParamTestWithDataProvider1.java
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class ParamTestWithDataProvider1
private PrimeNumberChecker primeNumberChecker;
@BeforeMethod
public void initialize()
primeNumberChecker = new PrimeNumberChecker();
@DataProvider(name = "test1")
public static Object[][] primeNumbers()
return new Object[][] 2, true , 6, false , 19, true ,
22, false , 23, true ;
// This test will run 4 times since we have 5 parameters defined
@Test(dataProvider = "test1")
public void testPrimeNumberChecker(Integer inputNumber,
Boolean expectedResult)
System.out.println(inputNumber + " " + expectedResult);
Assert.assertEquals(expectedResult,
primeNumberChecker.validate(inputNumber));
创建 TESTNG.XML
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite1">
<test name="test1">
<classes>
<class name="ParamTestWithDataProvider1" />
</classes>
</test>
</suite>
运行testng.xml.
验证输出。
2 true
6 false
19 true
22 false
23 true
===============================================
Suite1
Total tests run: 5, Failures: 0, Skips: 0
===============================================
实例 2
在这里,@DataProvider 传递对象作为参数。
创建Java类
创建一个Java类 Bean.java, 对象带有 get/set 方法
public class Bean
private String val;
private int i;
public Bean(String val, int i)
this.val=val;
this.i=i;
public String getVal()
return val;
public void setVal(String val)
this.val = val;
public int getI()
return i;
public void setI(int i)
this.i = i;
创建测试案例类
- 创建一个Java测试类 ParamTestWithDataProvider2.java.
- 定义方法primeNumbers(),其定义为DataProvider使用注释。此方法返回的对象数组的数组。
- 添加测试类中测试方法TestMethod()。此方法需要对象的bean作为参数。
- 添加注释 @Test(dataProvider = “test1”) 到此方法. dataProvider 属性被映射到 “test1”.
创建Java类文件名 ParamTestWithDataProvider2.java
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class ParamTestWithDataProvider2
@DataProvider(name = "test1")
public static Object[][] primeNumbers()
return new Object[][] new Bean("hi I am the bean", 111) ;
@Test(dataProvider = "test1")
public void testMethod(Bean myBean)
System.out.println(myBean.getVal() + " " + myBean.getI());
创建 TESTNG.XML
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite1">
<test name="test1">
<classes>
<class name="ParamTestWithDataProvider2" />
</classes>
</test>
</suite>
运行 testng.xml.
hi I am the bean 111
===============================================
Suite1
Total tests run: 1, Failures: 0, Skips: 0
===============================================
测试报告中自定义日志(Reporter.log(“输入自定义内容”)),例如:
@Test(groups = "人")
public void student()
System.out.println("学生方法被调用");
Reporter.log("学生方法自定义日志");
测试方法使用大全
TestNG预期异常测试
预期异常测试通过在@Test注解后加入预期的Exception来进行添加,范例如下所示:
@Test(expectedExceptions = ArithmeticException.class)
public void divisionWithException()
int i = 1 / 0;
System.out.println("After division the value of i is :"+ i);
运行结果如下:
[RemoteTestNG] detected TestNG version 6.10.0
[TestNG] Running:
C:\\Users\\Administrator\\AppData\\Local\\Temp\\testng-eclipse--754789457\\testng-customsuite.xml
PASSED: divisionWithException
===============================================
Default test
Tests run: 1, Failures: 0, Skips: 0
===============================================
===============================================
Default suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================
[TestNG] Time taken by org.testng.reporters.JUnitReportReporter@55d56113: 0 ms
[TestNG] Time taken by org.testng.reporters.SuiteHTMLReporter@1e127982: 0 ms
[TestNG] Time taken by org.testng.reporters.jq.Main@6e0e048a: 32 ms
[TestNG] Time taken by [FailedReporter passed=0 failed=0 skipped=0]: 0 ms
[TestNG] Time taken by org.testng.reporters.XMLReporter@43814d18: 0 ms
[TestNG] Time taken by org.testng.reporters.EmailableReporter2@6ebc05a6: 0 ms
TestNG忽略测试
有时候我们写的用例没准备好,或者该次测试不想运行此用例,那么删掉显然不明智,那么就可以通过注解@Test(enabled = false)来将其忽略掉,此用例就不会运行了,如下范例:
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");
运行结果:
this is TestNG test case2
PASSED: TestNgLearn2
TestNG超时测试
“超时”表示如果单元测试花费的时间超过指定的毫秒数,那么TestNG将会中止它并将其标记为失败。此项常用于性能测试。如下为一个范例:
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
结果如下:
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.以上是关于Java盲点攻克「TestNG专题」摒弃JUnit单元测试,带你学会使用TestNG测试框架(上篇)的主要内容,如果未能解决你的问题,请参考以下文章
JVM技术专题攻克你的技术盲点之Java的常量池们「 原理篇」
Java盲点攻克「时间与时区系列」让我们一起完全吃透对于时区和日期相关的功能开发原理
Java盲点攻克「直接内存IO流处理系列」深入分析和研究MappedByteBuffer的实现原理和开发指南