TestNG 使用流程

1、在 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>

2、新创建 Maven 项目,并在该项目中穿件 HelloWorld 文件

file:HelloWorld.java
1
2
3
4
5
public class HelloWorld {  
public String hello() {
return "hello world";
}
}

然后 alt+enter 选中类名即可快速生成 TestNG 测试类

file:HelloWorldTest
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class HelloWorldTest extends TestCase {  

@Test(enabled = false)
public void testHello1() {
HelloWorld hello = new HelloWorld();
String helloWorld = hello.hello();
// 检查返回结果
Assert.assertNotNull(helloWorld);
}

public void testHello2() {
HelloWorld hello = new HelloWorld();
String helloWorld = hello.hello();
System.out.println(helloWorld);
// 检查返回结果
Assert.assertEquals(helloWorld, "hello world");
}
}

3、执行后的效果

image.png

TestNG 常用注解

TestNG 注解执行顺序如下:@BeforeSuite > @BeforeTest > @BeforeMethod > @Test > @AfterMethod > @AfterTest > @AfterSuite

注解 作用
@BeforeSuite 在该套件的所有测试都运行在注释的方法之前,仅运行一次(套件测试是一起运行的多个测试类)
@AfterSuite 在该套件的所有测试都运行在注释方法之后,仅运行一次
@BeforeClass 在调用当前类的第一个测试方法之前运行,注释方法仅运行一次
@AfterClass 在调用当前类的第一个测试方法之后运行,注释方法仅运行一次
@BeforeTest 注释的方法将在属于标签内的类的所有测试方法运行之前运行
@AfterTest 注释的方法将在属于标签内的类的所有测试方法运行之后运行
@BeforeGroups 配置方法将在之前运行组列表。此方法保证在调用属于这些组中的任何一个的第一个测试方法之前不久运行
@AfterGroups 配置方法将在之后运行组列表。该方法保证在调用属于任何这些组的最后一个测试方法之后不久运行
@BeforeMethod 注释方法将在每个测试方法之前运行
@AfterMethod 注释方法将在每个测试方法之后运行
@Parameters 描述如何将参数传递给@Test 方法
@DataProvider 标记一种方法来提供测试方法的数据。注释方法必须返回一个 Object[][],其中每个 Object[] 可以被分配给测试方法的参数列表。要从该 DataProvider 接收数据的@Test 方法需要使用与此注释名称相等的 dataProvider 名称
@Factory 将一个方法标记为工厂,返回 TestNG 将被用作测试类的对象。该方法必须返回 Object[]
@Listeners 定义测试类上的侦听器
@Test 将类或方法标记为测试的一部分

[!example]

1、增加一个测试类 TestConfig

file:TestConfig.java
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
45
46
47
48
49
50
51
52
53
54
55
56
public class TestConfig {  
@BeforeSuite
public void beforeSuite(){
System.out.println("测试套件(当前xml中<suite>标签)之前运行@BeforeSuite------");
}

@AfterSuite
public void afterSuite(){
System.out.println("测试套(当前xml中<suite>标签)之后运行@AfterSuite-------");
}

@BeforeTest
public void beforeTest(){
System.out.println("测试用例(当前xml中<test>标签)之前运行@BeforeTest");
}

@AfterTest
public void afterTest(){
System.out.println("测试用例(当前xml中<test>标签)之后运行@AfterTest--------");
}

@BeforeMethod
public void beforeMethod(){
System.out.println("当前类每个测试方法(@Test)之前运行@BeforeMethod");
}

@AfterMethod
public void afterMethod(){
System.out.println("当前类每个测试方法(@Test)之后运行@AfterMethod");
}

@BeforeGroups(value="group1")
public void beforeGroups(){
System.out.println("配置组配group1之前运行@BeforeGroups..........");
}

@AfterGroups(value="group1")
public void afterGroups(){
System.out.println("配置组配group1之前运行@AfterGroups.......");
}

@Test
public void test1(){
System.out.println("running TestConfig.test1()");
}

@Test
public void test2(){
System.out.println("running TestConfig.test2()");
}

@Test(groups = "group1")
public void test3(){
System.out.println("running TestConfig.test3()");
}
}

2、使用插件 “Create TestNG XML” 可以快速生成 xml 文件来运行项目

3、在 testng.xml 文件中,通过 XML 标签的嵌套结构,可以定义和管理测试套件、测试组和测试类

file: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
<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<!--
@BeforeSuite: 在整个套件中的所有测试之前运行
@AfterSuite: 在整个套件中的所有测试之后运行
-->
<suite name="All Test Suite">
<!-- @BeforeTest: 在每个 <test> 元素中的所有类的测试方法之前运行 -->
<test name="case1">
<classes>
<!-- TestConfig 类的测试方法会首先执行 -->
<class name="com.myth.testcase.TestConfig"></class>
<!-- HelloWorldTest 类的测试方法会在 TestConfig 类之后执行 -->
<class name="com.myth.testcase.HelloWorldTest"></class>
</classes>
</test>
<!-- @AfterTest: 在每个 <test> 元素中的所有类的测试方法之后运行 -->

<!-- @BeforeTest: 在每个 <test> 元素中的所有类的测试方法之前运行 -->
<test name="case2">
<classes>
<!-- TestConfig 类的测试方法会在 case2 中执行 -->
<class name="com.myth.testcase.TestConfig"></class>
</classes>
</test>
<!-- @AfterTest: 在每个 <test> 元素中的所有类的测试方法之后运行 -->
</suite>
<!-- @AfterSuite: 在整个套件中的所有测试之后运行 -->

TestNG XML 标签

标签 作用
<suite> 套件,根标签,通常由几个 <test> 组成
<test> 测试用例,name 为必须属性
<classes> 用例中包含的类,字标签为<class name=”className”>
<class> 测试类,name 为必须属性
<packages> 用例中包含的包,包中所有的方法都会被执行,字标签为<package name=”packageName”>
<package> 测试包,name 为必须属性
<methods> 指定测试类中包含或排除的方法,字类为<include>,<exclude>
<include> 指定需要测试的方法
<exclude> 指定不需要测试的方法
<groups> 指定测试用例中要运行或者排除运行的分组,子标签为<run>,>,<run> 下包含 <include>,<exclude>标签,<include>,<exclude>的 name 指定运行、不运行的分组
file:tesng1.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
<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="tester">
<test name="case1">
<classes>
<class name="org.ant.test.testcase.TestHelloWorld"/>
<class name="org.ant.test.testcase.TestConfig">
<methods>
<include name="test1" /> <!-- 运行test1()方法-->
<exclude name="test2" /> <!-- 不运行test2()方法-->
</methods>
</class>
</classes>
</test>
<test name="case2">
<packages>
<package name="org.ant.test.testcase" />
</packages>
<groups>
<run>
<exclude name="group1" /> <!-- 不运行组group1的所有方法,或者也可include标签来表示需要行的组-->
</run>
</groups>
</test>
</suite>

suite 标签

TestNG.xml 文件的最外层标签即 suite,即测试套件,其下可以有多个 <test> 和 <groups>,可以添加的属性如下:

1、name 属性:必要属性,值可以自己设定,此名字会在 testNG 的报告中看到

2、verbose 属性:指定 TestNG 报告的详细程度,从 0 到 10,其中 10 最为详细;默认生成的 xml 次属性值为 1

3、parallel 属性:指代运行方式,默认为none,即串行运行方式;并行执行方法包括如下几种:

  • methods:方法层级,若为此值,则该suite下所有的测试方法都将进行多线程,即测试用例级别的多线程。如果用例之间有依赖,则执行顺序会按照设定的依赖来运行;
  • tests:TestNG将在同一线程中运行相同的 <Test> 标签中的所有方法,每个 <test>标签都将处于一个单独的线程中,这允许您将不是线程安全的所有类分组在同一个 <test> 中,并保证它们都将在同一个线程中运行,同时利用TestNG使用尽可能多的线程运行测试
  • classes:类级别并发,即 TestNG 会将该 suite 下每个 class 都将在单独的线程中运行,同一个 class 下的所有用例都将在同一个线程中运行;
  • instances:实例级别,即 TestNG 将在同一线程中运行同一实例中的所有方法,两个不同实例上的两个方法将在不同的线程中运行

4、thread-count 属性:指定线程数,按照需要输入,需要parallel参数非none时才可以添加

5、annotations 属性:为注解的级别,为methods级别和class级别,一般不用设置

6、time-out 属性:指定超时时间,该suite下所有的用例的超时时间

7、group-by-instances 属性:用于那些有依赖的方法,且被依赖的对象有多个重载对象,因为如果是依赖方法,且该方法有多个重载方法,则默认是会将所有重载方法都跑完再运行被依赖方法,但有时候我们不想这样,则将此项设置为true即可

8、preserve-order 属性:值可输入true或者false,如果为true,则用例执行会按照在xml中的顺序执行,否则会乱序执行,不添加此属性的话默认是按顺序执行的

test 标签

此标签无特别意义,其下可以包括多个标签,如groups、classes等,如下介绍下几种书写方式:

1、选择一个包中的全部测试脚本(包含子包)

1
2
3
4
5
<test name = "allTestsInAPackage" >
<packages>
<package name = "whole.path.to.package.* />
</packages>
</test>

2、选择一个类中的全部测试脚本

1
2
3
4
5
<test name = "allTestsInAPackage" >
<packages>
<package name = "whole.path.to.package.* />
</packages>
</test>

3、选择一个类中的部分测试脚本

1
2
3
4
5
6
7
8
9
10
11
<test name = "aFewTestsFromAClass" >
<classes>
<class name="whole.path.to.package.className >
<methods>
<include name = "firstMethod" />
<include name = "secondMethod" />
<include name = "thirdMethod" />
</methods>
</class>
</classes>
</test>

4、选择一个包中的某些组

1
2
3
4
5
6
7
8
9
10
<test name = "includedGroupsInAPackage" >
<groups>
<run>
<include name = "includedGroup" />
</run>
</groups>
<packages>
<package name = "whole.path.to.package.* />
</packages>
</test>

5、排除一个保中的某些组

1
2
3
4
5
6
7
8
9
10
<test name = "excludedGroupsInAPackage" >
<groups>
<run>
<exclude name = "excludedGroup" />
</run>
</groups>
<packages>
<package name = "whole.path.to.package.* />
</packages>
</test>

test 标签可以附带的属性有如下几种,下面对各个属性做单独说明:

1、name 属性:必须值,值可以自行设定,此名字只会在 TestNG 报告中展示

2、verbose 属性:指定testNG报告的详细程度,从0开始到10,其中10为最详细,默认生成的xml此属性值为1

3、threadPoolSize 属性:指定此test的线程池大小,为数字

4、invocationCount 属性:指定此test的运行次数,为数字,范例如上面的代码所示

5、time-out:指定此test的运行次数,为数字,范例如上面的代码所示

group 标签

此标签必然是在 <test> 标签下的,用于标识那些组会被用于测试或者被排除在测试之外,其同级必然要包含一个 <classes> 标签或者 <pakages> 标签,用于指定groups来自于哪些包或者类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<test name="Regression1">  
<groups>
<define name="functest">
<include name="windows"/>
<include name="linux"/>
</define>
<define name="all">
<include name="functest"/>
<include name="checkintest"/>
</define>
<run>
<include name="all"/>
</run>
</groups>
<classes>
<class name="test.sample.Test1"/>
</classes>
</test>

其他标签

1、选择一个包

1
2
3
<packages>
<package name = "packageName" />
</packages>

2、选择一个类

1
2
3
<classes>
<class name = "className" />
</classes>

3、选择一个方法

1
2
3
4
5
6
7
<classes>
<class name = "className" />
<methods>
<include name = "methodName" />
</methods>
</class>
</classes>

TestNG 常用断言

1、assertEquals():检查两个值是否相等

1
2
3
4
5
6
7
8
9
10
11
import org.testng.Assert;
import org.testng.annotations.Test;

public class ExampleTest {
@Test
public void testAssertEquals() {
int expected = 5;
int actual = 2 + 3;
Assert.assertEquals(actual, expected, "实际值与期望值不相等");
}
}

2、assertNotEquals():检查两个值是否不相等

1
2
3
4
5
6
@Test
public void testAssertNotEquals() {
int unexpected = 5;
int actual = 2 + 3;
Assert.assertNotEquals(actual, unexpected, "实际值与不期望值相等");
}

3、assertTrue():检查条件是否为真

1
2
3
4
5
@Test
public void testAssertTrue() {
boolean condition = (5 > 2);
Assert.assertTrue(condition, "条件应该为真");
}

4、assertFalse():检查条件是否为假

1
2
3
4
5
@Test
public void testAssertFalse() {
boolean condition = (5 < 2);
Assert.assertFalse(condition, "条件应该为假");
}

5、assertNull():检查对象是否为 null

1
2
3
4
5
@Test
public void testAssertNull() {
String str = null;
Assert.assertNull(str, "对象不应该是 null");
}

6、assertNotNull():检查对象是否不为 null

1
2
3
4
5
@Test
public void testAssertNotNull() {
String str = "Hello, TestNG!";
Assert.assertNotNull(str, "对象应该不为 null");
}

7、assertSame():检查两个引用是否指向同一个对象

1
2
3
4
5
6
@Test
public void testAssertSame() {
String str1 = new String("TestNG");
String str2 = str1;
Assert.assertSame(str1, str2, "两个引用不指向同一个对象");
}

8、assertNotSame():检查两个引用是否指向不同的对象

1
2
3
4
5
6
@Test
public void testAssertNotSame() {
String str1 = new String("TestNG");
String str2 = new String("TestNG");
Assert.assertNotSame(str1, str2, "两个引用应该指向不同的对象");
}

9、assertArrayEquals():检查两个数组是否相等(包括长度和元素)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ExampleTest {
@Test
public void testAssertArrayEquals() {
int[] expected = {1, 2, 3};
int[] actual = {1, 2, 3};

Assert.assertEquals(actual, expected, "数组不相等");
}

@Test
public void testAssertArrayEquals_Failure() {
int[] expected = {1, 2, 3};
int[] actual = {1, 2, 4}; // 这里将导致断言失败

Assert.assertEquals(actual, expected, "数组不相等,测试失败");
}
}

TestNG 参数传递

@Parameters

可以使用 @Parameters 注解从测试配置 xml 文件中获取参数

1、新建测试类 TestParameter

file:TestParameter.java
1
2
3
4
5
6
7
8
9
public class TestParameter {  

@Test
@Parameters({"param", "param2"})
public void printParameter(String param, String param2) {
System.out.println("param参数值为:" + param);
System.out.println("param2参数值为:" + param2);
}
}

2、创建 xml 文件,完成参数设置

paramterTest.xml
1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="parameterTest">
<test name="case1">
<parameter name="param" value="param的值"></parameter>
<parameter name="param2" value="param2的值"></parameter>
<classes>
<class name="com.myth.testcase.TestParameter"></class>
</classes>
</test>
</suite>


3、通过 xml 配置文件完成该测试方法的运行,结果如下

image.png

@DataProvider

此外,可以使用 @DataProvider 传送参数,@Dataprovider 可以传递一些比较复杂的参数

1、新建测试类 TestParameter2

file:TestParameter2.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class TestParameter2 {  

@DataProvider(name = "user")
public Object[][] Users() {
return new Object[][]{
{"root", "password"},
{"csdn.com", "zjkl"},
{"python", "java"}
};
}

@Test(dataProvider = "user")
public void verifyUser(String userName, String password) {
System.out.println("Username:" + userName + "Password:" + password);
}
}

2、运行之后得到结果

image.png

TestNG 预期异常测试

在 TestNG 中,可以使用 @Test 注解的 expectedExceptions 属性来指定预期的异常类型:如果测试方法抛出了指定的异常,测试将被视为通过;否则,测试将失败。

这种功能主要用于验证代码在异常情况下的行为是否符合预期。

1
2
3
4
5
6
7
8
public class TestException {  

@Test(expectedExceptions = ArithmeticException.class)
public void divisionWithException() {
int i = 1 / 0;
System.out.println("After division the value of i is :" + i);
}
}

image.png

TestNG 忽略测试

有时候我们写的用例没准备好,或者该次测试不想运行此用例,那么删掉显然不明智,那么就可以通过注解 @Test(enabled = false) 来将其忽略掉,此用例就不会运行了

1
2
3
4
5
6
7
8
9
10
11
12
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");
}
}

image.png

TestNG 超时测试

“超时”表示如果单元测试花费的时间超过指定的毫秒数,那么 TestNG 将会中止它并将其标记为失败。

此项常用于性能测试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
}
}
}

image.png

TestNG 分组测试

分组测试是指使用 group 属性进行测试分类。如果您使用 XML 配置文件,那么需要在 <groups> 标签中定义分组;如果直接在类中进行分组,则通过 @Test(groups="group2") 的方式来实现。

这种分组可以应用在单个测试方法上,也可以应用在类上。只要具有相同组名的测试方法或类,都会被归类到同一个组中。此外,组名可以指定多个,例如 @Test(groups = {"mysql", "database"})。

file:NewTest.java
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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");
}

@BeforeGroups(groups="group1")
public void beforeGroups()
{
System.out.println("beforeGroups");
}

@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");
}

}
file:TestCase.java
1
2
3
4
5
6
7
8
9
10
11
12
13
@Test(groups= "group2")
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");
}
}
file:testng.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<suite name="Suite" parallel="false">
<test name="Test">
<groups>
<include name="group1"></incloud>
<include name="group2"></incloud>
</groups>
<classes>
<class name="com.demo.test.testng.NewTest"/>
<class name="com.demo.test.testng.TestCase1"/>
</classes>
</test> <!-- Test -->
</suite> <!-- Suite -->

TestNG 分 suite 测试

测试套件是用于测试软件程序的行为或一组行为的测试用例的集合。在 TestNG 中,我们无法在测试源代码中定义一个套件,但它可以由一个 XML 文件表示,因为套件是执行的功能。它还允许灵活配置要运行的测试。套件可以包含一个或多个测试,并由 <suite> 标记定义。<suite> 是 testng. xml 的根标记。它描述了一个测试套件,它又由几个 <test> 部分组成。

TestNG 依赖测试

有时,我们可能需要以特定顺序调用测试用例中的方法,或者可能希望在方法之间共享数据和状态。 TestNG支持这种依赖关系,因为它支持在测试方法之间显式依赖的声明。

  • 在 @Test 注释中使用属性 dependsOnMethods
  • 在 @Test 注释中使用属性 dependsOnGroups

除此之外依赖还分为 hard 依赖和 soft 依赖:

  • hard 依赖:默认为此依赖方式,即其所有依赖的 methods 或者 groups 必须全部 pass,否则被标识依赖的类或者方法将会被略过,在报告中标识为 skip,如后面的范例所示,此为默认的依赖方式;
  • soft 依赖:此方式下,其依赖的方法或者组有不是全部 pass 也不会影响被标识依赖的类或者方法的运行,注意如果使用此方式,则依赖者和被依赖者之间必须不存在成功失败的因果关系,否则会导致用例失败。此方法在注解中需要加入 alwaysRun=true 即可,如 @Test (dependsOnMethods= {“TestNgLearn1”}, alwaysRun=true);

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");
}
}

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");
}
}

3、group 依赖

1
2
3
4
5
6
7
8
@Test(groups = { "init" })
public void serverStartedOk() {}

@Test(groups = { "init" })
public void initEnvironment() {}

@Test(dependsOnGroups = { "init.*" })
public void method1() {}

TestNG 报告

TestNG,默认测试报告在当前项目文件夹下的 test-output 文件夹内,index.html是汇总的测试测试报告,用浏览器打开就可以查看了;parameterTest 文件夹下是按测试用例生成的报告,old 文件夹下为历史报告

image.png

TestNG 功能汇总

功能 实现
测试注释 @Test
套件测试 标签
在套件中的所有测试运行之前运行 @BeforeSuite
在套件中的所有测试运行之后运行 @AfterSuite
测试之前运行 @BeforeTest
测试之后运行 @AfterTest
分组测试 @Test 的 group 参数
在调用属于任何这些组的第一个测试方法之前运行 @BeforeGroups
在调用属于任何这些组的第一个测试方法之后运行 @AfterGroups
在调用当前类的第一个测试方法之前运行 @BeforeClass
在调用当前类的第一个测试方法之后运行 @AfterClass
在每个测试方法之前运行 @BeforeMethod
在每个测试方法之后运行 @AfterMethod
预期的异常 @Test (expectedExceptions = ArithmeticException. class)
超时测试 @Test (timeout=1000)
参数化测试 @Parameters 或 DataProvider
依赖测试 @Test 的 dependsOnMethods 参数

TestNG 与 Junit4 区别

注释支持

特点 JUnit 4 TestNG
测试注释 @Test @Test
在套件中的所有测试运行之前运行 - @BeforeSuite
在套件中的所有测试运行之后运行 - @AfterSuite
测试之前运行 - @BeforeTest
测试之后运行 - @AfterTest
在调用属于任何这些组的第一个测试方法之前运行 - @BeforeGroups
在调用属于任何这些组的第一个测试方法之后运行 - @AfterGroups
在调用当前类的第一个测试方法之前运行 @BeforeClass @BeforeClass
在调用当前类的第一个测试方法之后运行 @AfterClass @AfterClass
在每个测试方法之前运行 @Before @BeforeMethod
在每个测试方法之后运行 @After @AfterMethod
忽略测试 @ignore @Test(enbale=false)
预期的异常 @Test(expected = ArithmeticException.class) @Test(expectedExceptions = ArithmeticException.class)
超时测试 @Test(timeout = 1000) @Test(timeout = 1000)

JUnit4 和 TestNG 之间的主要注释差异是:

  1. 在 JUnit4 中,必须声明 “@BeforeClass ”和“@AfterClass”方法作为静态方法。 TestNG在方法声明中更灵活,它没有这个约束
  2. 3 个额外的 setUp/tearDown 级别:test,suite 和 grouup
file:JUnit4
1
2
3
4
@BeforeClass public static void oneTimeSetUp() { 
// one-time initialization code
System.out.println("@BeforeClass - oneTimeSetUp");
}
file:TestNG
1
2
3
4
@BeforeClass public void oneTimeSetUp() { 
// one-time initialization code
System.out.println("@BeforeClass - oneTimeSetUp");
}

异常测试

“异常测试”是指从单元测试中抛出的异常,此功能在 JUnit 4 和 TestNG 中都可实现

file:JUint4
1
2
3
4
@Test(expected = ArithmeticException.class)
public void divisionWithException() {
int i = 1/0;
}
file:TestNG
1
2
3
4
@Test(expectedExceptions = ArithmeticException.class)
public void divisionWithException() {
int i = 1/0;
}

忽略测试

“忽略”表示是否应该忽略单元测试,该功能在JUnit 4和TestNG中均可实现

file:JUnit4
1
2
3
4
5
@Ignore("Not Ready to Run")
@Test
public void divisionWithException() {
System.out.println("Method is not ready yet");
}
file:TestNG
1
2
3
4
@Test(timeOut = 1000)
public void infinity() {
while (true);
}

时间测试

时间测试表示如果单元测试所花费的时间超过指定的毫秒数,则测试将会终止,并将其标记为失败,此功能在JUnit 4和TestNG中均可实现

file:JUnit4
1
2
3
4
@Test(timeout = 1000)
public void infinity() {
while (true);
}
file:TestNG
1
2
3
4
@Test(timeOut = 1000)
public void infinity() {
while (true);
}

套件测试

套件测试是指捆绑几个单元测试并一起运行。 此功能在JUnit 4和TestNG中都可实现。 然而,两者都使用非常不同的方法来实现它。

[!note] JUint4

@RunWith 和 @Suite。下面的类表示在 JunitTest5 执行之后,单元测试JunitTest1 和 JunitTest2 一起运行。所有的声明都是在类内定义的

file:Juint4
1
2
3
4
5
6
7
@RunWith(Suite.class)
@Suite.SuiteClasses({
JunitTest1.class,
JunitTest2.class
})
public class JunitTest5 {
}

``

[!note] TestNG

XML 文件用于运行套件测试。以下XML文件表示单元测试 TestNGTest1 和TestNGTest2将一起运行

1
2
3
4
5
6
7
8
<suite name="My test suite">
<test name="testing">
<classes>
<class name="com.fsecure.demo.testng.TestNGTest1" />
<class name="com.fsecure.demo.testng.TestNGTest2" />
</classes>
</test>
</suite>

TestNG可以做捆绑类测试,也可以捆绑方法测试。 凭借TestNG独特的“分组”概念,每种方法都可以与一个组合相结合,可以根据功能对测试进行分类(分组)。 例如,

下面是一个有四个方法的类,三个组( method1,method2 和 method3 )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Test(groups="method1")
public void testingMethod1() {
System.out.println("Method - testingMethod1()");
}

@Test(groups="method2")
public void testingMethod2() {
System.out.println("Method - testingMethod2()");
}

@Test(groups="method1")
public void testingMethod1_1() {
System.out.println("Method - testingMethod1_1()");
}

@Test(groups="method4")
public void testingMethod4() {
System.out.println("Method - testingMethod4()");
}

使用以下XML文件,可以仅使用组 method1 执行单元测试

1
2
3
4
5
6
7
8
9
10
11
12
<suite name="My test suite">
<test name="testing">
<groups>
<run>
<include name="method1"/>
</run>
</groups>
<classes>
<class name="com.fsecure.demo.testng.TestNGTest5_2_0" />
</classes>
</test>
</suite>

通过“分组”测试概念,集成测试的可能性是无限制的。例如,我们只能从所有单元测试类中测试 DatabaseFuntion 分组

参数化测试

参数化测试是指单位测试参数值的变化。 此功能在JUnit 4和TestNG中都实现。 然而,两者都使用非常不同的方法来实现它

[!note] JUint4

@RunWitch 和@Parameter 用于提供单元测试的参数值,@Parameters 必须返回 List[],参数将作为参数传入类构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@RunWith(value = Parameterized.class)
public class JunitTest6 {

private int number;

public JunitTest6(int number) {
this.number = number;
}

@Parameters
public static Collection<Object[]> data() {
Object[][] data = new Object[][] { { 1 }, { 2 }, { 3 }, { 4 } };
return Arrays.asList(data);
}

@Test
public void pushTest() {
System.out.println("Parameterized Number is : " + number);
}
}

这里有很多限制,我们必须遵循 JUnit 的方式来声明参数,并且必须将参数传递给构造函数才能初始化类成员作为测试的参数值。参数类的返回类型为 List [],数据已被限制为String或用于测试的原始类型值。

[!note] TestNG

XML 文件或者 @DataProvider 用于提供不同参数进行测试:

只有 @Parameters 在需要参数测试的方法中声明,参数化数据将在 TestNG 的 XML 配置文件中提供。通过这样做,我们可以使用不同数据集的单个测试用例,甚至获得不同的结果。另外,即使是最终用户,QA 还是 QE 都可以在 XML 文件中提供自己的数据进行测试

1
2
3
4
5
6
7
8
public class TestNGTest6_1_0 {

@Test
@Parameters(value="number")
public void parameterIntTest(int number) {
System.out.println("Parameterized Number is : " + number);
}
}
1
2
3
4
5
6
7
8
9
10
<suite name="My test suite">
<test name="testing">

<parameter name="number" value="2"/>

<classes>
<class name="com.fsecure.demo.testng.TestNGTest6_0" />
</classes>
</test>
</suite>

@DataProvider 用于参数化测试:

将数据值拉入XML文件可能非常方便,但测试偶尔会需要复杂的类型,这些类型不能被表示为一个字符串或一个原始类型值。TestNG 使用 @DataProvider 注解来处理这种情况,这有助于将复杂参数类型映射到测试方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Test(dataProvider = "Data-Provider-Function")
public void parameterIntTest(Class clzz, String[] number) {
System.out.println("Parameterized Number is : " + number[0]);
System.out.println("Parameterized Number is : " + number[1]);
}

//This function will provide the patameter data
@DataProvider(name = "Data-Provider-Function")
public Object[][] parameterIntTestProvider() {
return new Object[][]{
{Vector.class, new String[] {"java.util.AbstractList",
"java.util.AbstractCollection"}},
{String.class, new String[] {"1", "2"}},
{Integer.class, new String[] {"1", "2"}}
};
}

@DataProvider 作为对象的参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Test(dataProvider = "Data-Provider-Function")
public void parameterIntTest(TestNGTest6_3_0 clzz) {
System.out.println("Parameterized Number is : " + clzz.getMsg());
System.out.println("Parameterized Number is : " + clzz.getNumber());
}

//This function will provide the patameter data
@DataProvider(name = "Data-Provider-Function")
public Object[][] parameterIntTestProvider() {

TestNGTest6_3_0 obj = new TestNGTest6_3_0();
obj.setMsg("Hello");
obj.setNumber(123);

return new Object[][]{
{obj}
};
}

TestNG的参数化测试非常用户友好和灵活(在 XML 文件或类内),它可以支持许多复杂的数据类型作为参数值,可能性是无限的。如上例所示,我们甚至可以传入我们自己的对象TestNGTest6_3_0进行参数化测试

依赖性测试

表示方法是依赖性测试,它将在所需方法之前执行。 如果依赖方法失败,则所有后续测试将会被跳过,不会被标记为失败

JUint4:JUnit框架着重于测试隔离; 目前它不支持此功能

TestNG:使用 dependsOnMethod 来实现依赖测试:

1
2
3
4
5
6
7
8
9
@Test
public void method1() {
System.out.println("This is method 1");
}

@Test(dependsOnMethods={"method1"})
public void method2() {
System.out.println("This is method 2");
}

method2() 只有在 method1() 运行成功下才会执行,否则 method2()将跳过测试