目錄
前言
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 | 在該套件的所有測試運行之後運行,僅運行一次 |
@BeforeClass | 在調用當前類的第一個測試方法之前運行,僅運行一次 |
@AfterClass | 在調用當前類的第一個測試方法之後運行,僅運行一次 |
@BeforeTest | 註釋的方法將在屬於test標籤內的類的所有測試方法運行之前運行 |
@AfterTest | 註釋的方法將在屬於test標籤內的類的所有測試方法運行之後運行 |
@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->@Test1->@AfterMethod,@BeforeMethod->@Test2->@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");
}
@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");
}
@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
testC03
testC04
beforeTest
beforeClass
beforeMethod
testD03
afterMethod
beforeMethod
testD04
afterMethod
beforeMethod
testD05
afterMethod
afterClass
afterTest
===============================================
Suite
Total tests run: 5, 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>
<incloud name="group1"></incloud>
<incloud 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最詳細 |
parallel | TestNG是否運行不同的線程來運行這個套件,默認爲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中指明則每次運行的順序不能保證。
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的模板,並在上圖中指定。
14. 與Junit的區別
參考文章: