【TestNG】TestNG使用教程詳解
一、TestNG介紹
TestNG是Java中的一個測試框架, 類似於JUnit 和NUnit, 功能都差不多, 只是功能更加強大,使用也更方便。
詳細使用說明請參考官方連結:https://testng.org/doc/index.html
二、TestNG安裝(基於eclipse+maven)
工程的pom.xml中需要新增如下內容:
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
< version>6.10</version>
<scope>test</scope>
</dependency>
記得Maven install一下
eclipse中的TestNG外掛的安裝則需要在Help中做,地址為http://beust.com/eclipse
;
三、TestNG基本使用和執行
新建一個maven工程,新建一個TestNG的class,可以直接新建一個class來使用,也可以新建一個TestNG的class,如下圖所示:
此方法好處在於你在建立class的時候可以直接把註解的各個方法都加進去,同時也可以建立xml,名字路徑可以自己定義,注意xml檔案的路徑是支援相對路徑的,出來的class檔案如下所示:
package com.demo.test.testng;
import org.testng.annotations.Test;
public class NewTest {
@Test
public void f() {
}
}
一個簡單的用例如下:
package com.demo.test.testng;
import org.testng.Assert;
import org.testng.annotations.Test;
public class NewTest {
@Test
public void f() {
System. out.println("this is new test");
Assert.assertTrue(true);
}
}
1、直接執行:
結果如下:
[RemoteTestNG] detected TestNG version 6.10.0
[TestNG] Running:
C:\Users\aaa\AppData\Local\Temp\testng-eclipse-342998054\testng-customsuite.xml
this is new test
PASSED: f
===============================================
Default test
Tests run: 1, Failures: 0, Skips: 0
===============================================
===============================================
Default suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================
[TestNG] Time taken by [email protected]: 4 ms
[TestNG] Time taken by [email protected]: 26 ms
[TestNG] Time taken by [email protected]: 20 ms
[TestNG] Time taken by [FailedReporter passed=0 failed=0 skipped=0]: 0 ms
[TestNG] Time taken by [email protected]: 3 ms
[TestNG] Time taken by [email protected]: 2 ms
2、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 -->
執行方法:
右鍵該xml選擇Run As–>TestNG Suite,如下:
執行結果如下:
[RemoteTestNG] detected TestNG version 6.10.0
[TestNGContentHandler] [WARN] It is strongly recommended to add "<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >" at the top of your file, otherwise TestNG may fail or not work as expected.
[XmlSuite] [WARN] 'parallel' value 'false' is deprecated, default value will be used instead: 'none'.
[TestNG] Running:
D:\software\workspace\testng\src\main\java\com\demo\test\testCase\newTestXML.xml
this is new test
===============================================
Suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================
3、
四、註解說明
TestNG支援多種註解,可以進行各種組合,如下進行簡單的說明
註解 | 描述 |
---|---|
@BeforeSuite | 在該套件的所有測試都執行在註釋的方法之前,僅執行一次 |
@AfterSuite | 在該套件的所有測試都執行在註釋方法之後,僅執行一次 |
@BeforeClass | 在呼叫當前類的第一個測試方法之前執行,註釋方法僅執行一次 |
@AfterClass | 在呼叫當前類的第一個測試方法之後執行,註釋方法僅執行一次 |
@BeforeTest | 註釋的方法將在屬於test標籤內的類的所有測試方法執行之前執行 |
@AfterTest | 註釋的方法將在屬於test標籤內的類的所有測試方法執行之後執行 |
@BeforeGroups | 配置方法將在之前執行組列表。 此方法保證在呼叫屬於這些組中的任何一個的第一個測試方法之前不久執行 |
@AfterGroups | 此配置方法將在之後執行組列表。該方法保證在呼叫屬於任何這些組的最後一個測試方法之後不久執行 |
@BeforeMethod | 註釋方法將在每個測試方法之前執行 |
@AfterMethod | 註釋方法將在每個測試方法之後執行 |
@DataProvider | 標記一種方法來提供測試方法的資料。 註釋方法必須返回一個Object [] [] ,其中每個Object [] 可以被分配給測試方法的引數列表。 要從該DataProvider 接收資料的@Test 方法需要使用與此註釋名稱相等的dataProvider 名稱 |
@Factory | 將一個方法標記為工廠,返回TestNG 將被用作測試類的物件。 該方法必須返回Object [] |
@Listeners | 定義測試類上的偵聽器 |
@Parameters | 描述如何將引數傳遞給@Test 方法 |
@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斷言
TestNG的斷言種類很多,包括相等/不相等,true/false、為null/不為null、相同/不相同等。
六、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 [email protected]: 0 ms
[TestNG] Time taken by [email protected]: 0 ms
[TestNG] Time taken by [email protected]: 32 ms
[TestNG] Time taken by [FailedReporter passed=0 failed=0 skipped=0]: 0 ms
[TestNG] Time taken by [email protected]: 0 ms
[TestNG] Time taken by [email protected]: 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.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)
九、分組測試
分組測試即為使用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也加進來,不被加進去的不會執行;
十、分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 | 在本測試中的所有測試方法上使用的預設超時 |
十一、依賴測試
有時,我們可能需要以特定順序呼叫測試用例中的方法,或者可能希望在方法之間共享一些資料和狀態。 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.run