TestNG单元测试框架详解

目录

前言

1. TestNG使用流程

1.1TestNG安装

1.2 创建Maven项目

1.3 Maven配置

1.4 项目TestNG测试类

1.5 运行TestNG

2、TestNG常用注解

3.xml方式运行

3.1 鼠标右击testng.xml运行

3.1 使用maven运行

4. 常用的断言(assert)

5. TestNG预期异常测试

6. TestNG忽略测试

7. TestNG超时测试

8. 分组测试

9. 分suite测试

10. 依赖测试

11. 参数化测试

12. XML配置文件说明

13. TestNG报告

14. 与Junit的区别


前言

TestNG是一个java中的开源自动化测试框架,其灵感来自JUnit和NUnit,TestNG还涵盖了JUnit4整个核心的功能,但引入了一些新的功能,使其功能更强大,使用更方便。

优势:支持依赖测试方法,并行测试,负载测试,局部故障,灵活的插件API,支持多线程测试。详细使用说明请参考官方链接:TestNG官方文档

1. TestNG使用流程

1.1TestNG安装

本文以IDEA+Maven为例介绍TestNG,IntelliJ IDEA版本为IntelliJ IDEA 2020.1.1 (Ultimate Edition)。

IntelliJ IDEA中默认集成了TestNG,点击File->Settings,如下图:

1.2 创建Maven项目

点击File->new-Project,如图

创建基于Maven的项目

创建名字为MavenTest的项目,创建完成后如下图

1.3 Maven配置

在工程的pom.xml中需要添加如下依赖:

<?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

添加一个测试方法,如下

运行结果如下:

2、TestNG常用注解

有必要介绍一下TestNG注解的生命周期,先看一下官网支持的注解有 :

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

如上列表中的@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运行时,顺序是这样的:

@BeforeSuite->@BeforeTest->@BeforeClass->{@BeforeGroups[@BeforeMethod->@Test1->@AfterMethod,@BeforeMethod->@Test2->@AfterMethod, ...]@AfterGroups, @BeforeGroups[@BeforeMethod->@Test3->@AfterMethod,@BeforeMethod->@Test4->@AfterMethod, ...]@AfterGroups, ...}->@AfterClass->@AfterTest->@AfterSuite

其中{}内将@BeforeGroups@AfterGroups将@Test分组,每个分组内包含多个@Test。

3.xml方式运行

TestNG也可以以xml的方式运行

<suite>  套件,根标签,通常由几个<test组成>
  属性:
  name            套件的名称,必须属性;
  verbose         运行的级别或详细程度;
  parallel        是否运行多线程来运行这个套件;
  thread-count    如果启用多线程,用于指定开户的线程数;
  annotations     在测试中使用的注释类型;
  time-out        在本测试中的所有测试方法上使用的默认超时时间; 
<test>    测试用例,name为必须属性;
<classes>  用例中包含的类,子标签为<class name=”className”>;
<class>    测试类,其中属性name为必须属性;;
<packages> 用例中包含的包,包中所有的方法都会执行,子标签为<package name=”packageName”>;
<package>  测试包,name为必须属性;
<methods>  指定测试类中包含或排除的方法,子类为<include>,<exclude>;
<include>  指定需要测试的方法,name为必须属性;
<exclude>  指定类中不需要测试的方法,name为必须属性;
<groups>   指定测试用例中要运行或排除运行的分组,子标签为<run>,<run>下包含<include>,<exclude>标签,<include>,<exclude>的name指定运行、不运行的分组;

在项目下新建一个testng.xml文件,模板如下:

<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd" >
  
<suite name="Suite1" verbose="1" >
  <test name="Nopackage" >
    <classes>
       <class name="NoPackageTest" />
    </classes>
  </test>
 
  <test name="Regression1">
    <classes>
      <class name="test.sample.ParameterSample"/>
      <class name="test.sample.ParameterTest"/>
    </classes>
  </test>
</suite>

3.1 鼠标右击testng.xml运行

TestTest3的代码如下:

import org.testng.Assert;
import org.testng.annotations.Test;
import org.testng.annotations.*;


public class TestTest3 {


    @Test(groups = "group1")
    public void testC03() {
        System.out.println("testC03");
        Assert.assertTrue(true);
    }

    @Test(groups = "group1")
    public void testC04() {
        System.out.println("testC04");
        Assert.assertTrue(true);
    }

    @Test(groups = "group2")
    public void testC05() {
        System.out.println("testC05");
        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", "group2"})
    public void beforeGroups() {
        System.out.println("beforeGroups");
    }

    @AfterGroups(groups = {"group1", "group2"})
    public void afterGroups() {
        System.out.println("afterGroups");
    }


    @BeforeMethod
    public void beforeMethod() {
        System.out.println("beforeMethod");
    }

    @AfterMethod
    public void afterMethod() {
        System.out.println("afterMethod");
    }
}

TestTest4的代码如下:

import org.testng.Assert;
import org.testng.annotations.Test;
import org.testng.annotations.*;


public class TestTest4 {


    @Test(groups = "group1")
    public void testD03() {
        System.out.println("testD03");
        Assert.assertTrue(true);
    }

    @Test(groups = "group1")
    public void testD04() {
        System.out.println("testD04");
        Assert.assertTrue(true);
    }

    @Test(groups = "group2")
    public void testD05() {
        System.out.println("testD05");
        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");
    }

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

修改testng.xml的内容如下:

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="Suite" parallel="none">
    <test name="Test">
<!--        <groups>-->
<!--            <run>-->
<!--                <include name="group1"/>-->
<!--            </run>-->
<!--        </groups>-->

        <classes>
            <class name="TestTest3"/>
        </classes>

    </test> <!-- Test -->

    <test name="Test2">
        <classes>
            <class name="TestTest4"/>
        </classes>
    </test> <!-- Test -->

</suite> <!-- Suite -->

鼠标右键testng.xml文件,运行结果如下:

[TestNG] Running:
  C:\Users\HP\IdeaProjects\MavenTest\testng.xml

beforeSuite

beforeTest

beforeClass

beforeGroups

beforeMethod

testC03

afterMethod

beforeMethod

testC04

afterMethod

afterGroups

beforeGroups

beforeMethod

testC05

afterMethod

afterGroups

afterClass

afterTest


beforeTest

beforeClass

beforeGroups

beforeMethod

testD03

afterMethod

beforeMethod

testD04

afterMethod

afterGroups

beforeMethod

testD05

afterMethod

afterClass

afterTest

afterSuite


===============================================
Suite
Total tests run: 6, Failures: 0, Skips: 0
===============================================


Process finished with exit code 0

3.1 使用maven运行

需要在pom文件中,指明testng.xml文件的位置。

maven使用surefire这个插件进行测试,可以执行testng或者Junit脚本。

语法为 <suiteXmlFile>src/test/resources/testNGFilesFolder/${testNgFileName}.xml</suiteXmlFile> 

<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>

运行测试脚本

进入到项目工程的根目录,使用 mvn clean test -Dtestng.xml 命令。

4. 常用的断言(assert)

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.;

5. 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

6. 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

7. 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.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)

8. 分组测试

分组测试即为使用group,如果你使用xml的话就是里边的<groups>标签,如果是直接在class中,是通过@Test(groups="group2")这种方式来分组,如第四节的注解说明中的那个例子,分了两个group,而且@BeforeGroup是需要添加group名称才可以正确挂载到该group下的;
这个group说明可以是在单个的测试方法上,也可以在class上,只要具有同样的group名称都会在同一个group中,同时group名称可以有多个,类似@Test(groups = {"mysql","database"})这种,范例如下:
一个测试文件NewTest.class:
 

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

另一个TestCase1.class:

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

xml如下:

<?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 -->

运行结果如下:

beforeSuite
beforeTest
beforeClass
beforeGroups
beforeMethod
test1 from group1
afterMethod
beforeMethod
test11 from group1
afterMethod
afterGroups
beforeMethod
test2 from group2
afterMethod
afterClass
this is TestNG test case2
afterTest
afterSuite

如上所示,先运行了group1的两个用例,再运行group2的两条用例;
注意在xml标识group,需要将要运行的group加进来,同时还要将被标识这些group的class也加进来,不被加进去的不会运行。

9. 分suite测试

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

属性描述
name套件的名称,这是一个强制属性
verbose运行的级别或详细程度,级别为0-10,其中10最详细
parallelTestNG是否运行不同的线程来运行这个套件,默认为none,其他级别为methods、tests、classes、instances
thread-count如果启用并行模式(忽略其他方式),则为使用的线程数
annotations在测试中使用的注释类型
time-out在本测试中的所有测试方法上使用的默认超时

10. 依赖测试

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

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

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

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

在TestNG中,我们使用dependOnMethods和dependsOnGroups来实现依赖测试。 且这两个都支持正则表达式,如范例三所示,如下为几个使用范例:

  • 范例一,被依赖方法pass:
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");
    }
}

运行结果:

this is TestNG test case1
this is TestNG test case2
PASSED: TestNgLearn1
PASSED: TestNgLearn2

  • 范例二,被依赖方法fail:
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");
    }
}

结果:

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

范例三、group依赖:
如下所示,method1依赖group名称为init的所有方法:

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

这里init这个group中的两个方法的执行顺序如果没有在xml中指明则是按照方法名英文字母的字典顺序执行的。

关于TestNG框架测试用例的执行顺序请查看我的另一篇博客:TestNG框架测试用例的执行顺序分析

11. 参数化测试

TestNG中的另一个有趣的功能是参数化测试。 在大多数情况下,您会遇到业务逻辑需要大量测试的场景。 参数化测试允许开发人员使用不同的值一次又一次地运行相同的测试。
TestNG可以通过两种不同的方式将参数直接传递给测试方法:

  • 使用testng.xml
  • 使用数据提供者

下面分别介绍两种传参方式:
1、使用textng.xml传送参数
范例代码如下:

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配置:

<?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,结果如下:

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[][],此处需要注意。
代码如下:

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,结果为:

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


12. XML配置文件说明

前面讲的大多都是以测试脚本为基础来运行的,少部分是以xml运行,这里以xml来讲解下:

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="SuiteName" verbose="1" > 

如下分别讲解各个标签:

1、suite标签
testNG.xml文件的最外层标签即suite,即测试套件,其下可以有多个<test>和<groups>,其有几个可以添加的属性在第十节的分suite测试中有做说明,这里做下详细说明:

(1)、name属性
此属性属于必须要有的,值可以自行设定,此名字会在testNG的报告中看到;

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

(3)、parallel属性
此属性是指代运行方式,默认为none,即串行运行方式;并行执行方法包括如下几种,下面做分别说明:

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


(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中的顺序执行,否则会乱序执行,不添加此属性的话默认是按顺序执行的;

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

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

<test name = "allTestsInAPackage" >
   <packages>
      <package name = "whole.path.to.package.* />
   </packages>
</test>

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

<test name = "allTestsInAPackage" >
   <packages>
      <package name = "whole.path.to.package.* />
   </packages>
</test>

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

<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)选择一个包中的某些组

<test name = "includedGroupsInAPackage" >
   <groups>
      <run>
         <include name = "includedGroup" />
      </run>
   </groups>
   <packages>
      <package name = "whole.path.to.package.* />
   </packages>
</test>

(5)排除一个包中的某些组

<test name = "excludedGroupsInAPackage" >
   <groups>
      <run>
         <exclude name = "excludedGroup" />
      </run>
   </groups>
   <packages>
      <package name = "whole.path.to.package.* />
   </packages>
</test>

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

(1)、name属性
此属性属于必须要有的,值可以自行设定,此名字会在testNG的报告中看到;

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

(3)、threadPoolSize属性
该属性指定此test的线程池大小,为数字;

<test name = "excludedGroupsInAPackage" >
   <groups>
      <run>
         <exclude name = "excludedGroup" />
      </run>
   </groups>
   <packages>
      <package name = "whole.path.to.package.* />
   </packages>
</test>

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

(5)、time-out属性
此属性用于指定超时时间,该suite下所有的用例的超时时间,范例如上面的代码所示;

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

<suite name="Factory" group-by-instances="true">

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

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

<groups>
  <run>
     <include name = "includedGroupName" />
     <exclude name = "excludedGroupName" />
  </run>
</groups>

高级应用:

<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>

4、其他
其他的话就是测试脚本的选择了,有三种方式:

(1)选择一个包

<packages>
    <package name = "packageName" />
</packages>

(2)选择一个类

<classes>
    <class name = "className" />
</classes>

(3)选择一个方法

<classes>
    <class name = "className" />
       <methods>
          <include name = "methodName" />
       </methods>
    </class>
</classes>

这里也支持正则表达式,例如:

<test name="Test1">
  <classes>
    <class name="example1.Test1">
      <methods>
        <include name=".*enabledTestMethod.*"/>
        <exclude name=".*brokenTestMethod.*"/>
      </methods>
     </class>
  </classes>
</test>


13. TestNG报告

默认报告输出位置为当前工程的test-output文件夹下,包括xml格式和html格式。
如果想要美化报告,则按照如下步骤:
1、配置:Eclipse --> Window --> Preferences -->testng
2、勾选Disable default listeners
3、在Pre Defined Listeners 输入框中输入org.uncommons.reportng.HTMLReporter
记得在POM上添加如下代码:

<dependency>
      <groupId>org.uncommons</groupId>
      <artifactId>reportng</artifactId>
      <version>1.1.4</version>
      <scope>test</scope>
      <exclusions>
        <exclusion>
          <groupId>org.testng</groupId>
          <artifactId>testng</artifactId>
        </exclusion>
      </exclusions>
     </dependency>
     <dependency>
       <groupId>com.google.inject</groupId>
       <artifactId>guice</artifactId>
       <version>3.0</version>
       <scope>test</scope>
     </dependency>

不然无法运行的。
如上图所示,还可以自定义testng.xml的模板,并在上图中指定。

使用IDEA+TestNG进行测试,没有生成 测试报告,是因为没有勾选监听器使用默认报告,具体操作如下:

“Run” -> "Edit Configurations" -> "listeners" -> "Use default reporters"

输出报告在test-output文件夹中(index.html)。

14. 与Junit的区别

 有兴趣可以关注我的微信公众号“自动化测试全栈”,微信号:QAlife,学习更多自动化测试技术。

也可加入我们的自动化测试技术交流群,QQ群号码:301079813

主要探讨loadrunner/JMeter测试、Selenium/RobotFramework/Appium自动化测试、接口自动化测试,测试工具等测试技术,让我们来这里分享经验、交流技术、结交朋友、拓展视野、一起奋斗!

参考文章:

1. 【TestNG】TestNG使用教程详解_df0128的专栏-CSDN博客_testng

2.TestNG入门到... - 覆手为云p - 博客园

  • 81
    点赞
  • 663
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
Java TestNG是一种用于编写和执行单元测试框架。它可以帮助开发人员进行自动化测试,并提供了丰富的功能和灵活的配置选项。 在Java TestNG中,可以使用@Test注解来标记测试方法。通过使用不同的注解参数,可以控制测试方法的执行顺序、分组和依赖关系。 引用\[1\]中的示例展示了一个使用@Test注解的测试类TestCase1。其中,@Test(enabled=false)表示该测试方法不会被执行,而@Test表示该测试方法会被执行。通过这种方式,可以选择性地执行测试方法。 引用\[2\]中的示例展示了如何使用priority参数来控制测试方法的执行顺序。priority的数值越小,优先级越高,测试方法会按照优先级从小到大的顺序执行。 引用\[3\]中的示例展示了如何使用dependsOnMethods参数来定义测试方法之间的依赖关系。在这个示例中,TestNgLearn2方法依赖于TestNgLearn1方法,只有在TestNgLearn1方法执行成功后,TestNgLearn2方法才会被执行。 总结来说,Java TestNG可以通过注解参数来控制测试方法的执行顺序、分组和依赖关系,从而实现灵活的单元测试。 #### 引用[.reference_title] - *1* *3* [TestNG单元测试框架详解](https://blog.csdn.net/lovedingd/article/details/106784561)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Java笔记-单元测试框架TestNG](https://blog.csdn.net/qq_19645167/article/details/126280996)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

慕城南风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值