TestNG介紹
TestNG是Java中的一個測試框架, 類似於JUnit 和NUnit, 功能都差不多, 只是功能更加強大,使用也更方便。
詳細使用說明請參考官方連結:https://testng.org/doc/index.html
TestNG安裝
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.10</version>
<scope>test</scope>
</dependency>
TestNG的優點
- 漂亮的HTML格式測試報告
- 支援併發測試
- 引數化測試更簡單
- 支援輸出日誌
- 支援更多功能的註解
編寫TestNG測試用例的步驟
-
使用 Eclipse生成TestNG的測試程式框架
-
在生成的程式框架中編寫測試程式碼邏輯
-
根據測試程式碼邏輯,插入TestNG註解標籤
-
配置Testng.xml檔案,設定測試類、測試方法、測試分組的執行資訊
-
執行TestNG的測試程式
TestNG的簡單用例
Java直接執行
package com.demo.test.testng;
import org.testng.annotations.Test;
public class NewTest {
@Test
public void testFunction() {
System.out.println("this is new test");
Assert.assertTrue(true);
}
}
xml方式執行
由於我將xml放置在其他資料夾,不和class放在一個資料夾,所以需要修改xml,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<suite name="Suite" parallel="false">
<test name="Test">
<classes>
<class name="com.demo.test.testng.NewTest"/>
</classes>
</test> <!-- Test -->
</suite> <!-- Suite -->
TestNG的註解
TestNG支援多種註解,可以進行各種組合,如下進行簡單的說明
@BeforeSuite > @BeforeTest > @BeforeMethod > @Test > @AfterMethod > @AfterTest > @AfterSuite
如上列表中的@Factory、@Linsteners這兩個是不常用的;
前十個註解看起來不太容易區分,順序不太容易看明白,以如下範例做簡單說明,程式碼
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterGroups;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
public class NewTest {
@Test(groups="group1")
public void test1() {
System.out.println("test1 from group1");
Assert.assertTrue(true);
}
@Test(groups="group1")
public void test11() {
System.out.println("test11 from group1");
Assert.assertTrue(true);
}
@Test(groups="group2")
public void test2()
{
System.out.println("test2 from group2");
Assert.assertTrue(true);
}
@BeforeTest
public void beforeTest()
{
System.out.println("beforeTest");
}
@AfterTest
public void afterTest()
{
System.out.println("afterTest");
}
@BeforeClass
public void beforeClass()
{
System.out.println("beforeClass");
}
@AfterClass
public void afterClass()
{
System.out.println("afterClass");
}
@BeforeSuite
public void beforeSuite()
{
System.out.println("beforeSuite");
}
@AfterSuite
public void afterSuite()
{
System.out.println("afterSuite");
}
//只對group1有效,即test1和test11
@BeforeGroups(groups="group1")
public void beforeGroups()
{
System.out.println("beforeGroups");
}
//只對group1有效,即test1和test11
@AfterGroups(groups="group1")
public void afterGroups()
{
System.out.println("afterGroups");
}
@BeforeMethod
public void beforeMethod()
{
System.out.println("beforeMethod");
}
@AfterMethod
public void afterMethod()
{
System.out.println("afterMethod");
}
}
執行結果如下:
beforeSuite
beforeTest
beforeClass
beforeGroups
beforeMethod
test1 from group1
afterMethod
beforeMethod
test11 from group1
afterMethod
afterGroups
beforeMethod
test2 from group2
afterMethod
afterClass
afterTest
PASSED: test1
PASSED: test11
PASSED: test2
===============================================
Default test
Tests run: 3, Failures: 0, Skips: 0
===============================================
afterSuite
如何建立TestNG測試集合?
- 在自動化測試的執行過程中,通常會產生批量執行多個測試用例的需求,此需求稱為執行測試集合(Test Suite)
- TestNG的測試用例可以是相互獨立的,也可以按照特定的順序來執行(配置TestNG.xml)
如何配置testNG.xml檔案?
<suite name = "TestNG Suite"> //自定義的測試集合名稱
<test name = "test1"> //自定義的測試名稱
<classes> //定義被執行的測試類
<class name = "cn.gloryroad.FirstTestNGDemo" /> //測試類的路徑
<class name = "cn.gloryroad.NewTest" />
</classes>
</test>
</suite>
測試用例的分組(group)
執行組分組配置如下:
<suite name = "TestNG Suite">
<test name = "Grouping">
<groups>
<run>
<include name = "動物" />
</run>
</groups>
<classes>
<class name = "cn.gloryroad.Grouping"/>
</classes>
</test>
</suite>
執行多組分組時配置如下(兩種形式都可以):
<suite name = "TestNG Suite">
<test name = "Grouping">
<groups>
<run>
<include name = "動物" /> //name分組名稱
<include name = "人" />
</run>
</groups>
<classes>
<class name = "cn.gloryroad.Grouping"/>
</classes>
</test>
</suite>
依賴測試(dependsOnMethod)
被依賴的方法優先於此方法執行
@Test(dependsOnMethod = {"方法名稱"})
特定順序執行測試用例(priority)
按照數字大小順序優先執行,優先執行1,然後是2…
@Test(priority = 0/1/2/3/4/…)
如何跳過某個測試方法(enabled = false)
@Test(priority = 0/1… , enabled = false)
執行結束後,在測試報告中顯示跳過的測試用例數,例如skip=1
建立測試案例類
- 建立一個Java測試類 ParameterizedTest1.java.
- 測試方法parameterTest()新增到測試類。此方法需要一個字串作為輸入引數。
- 新增註釋 @Parameters("myName") 到此方法。該引數將被傳遞testng.xml,在下一步我們將看到一個值。
建立Java類檔名 ParameterizedTest1.java
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
public class ParameterizedTest1 {
@Test
@Parameters("myName")
public void parameterTest(String myName) {
System.out.println("Parameterized value is : " + myName);
}
}
建立 TESTNG.XML
建立 testng.xml C:\ > TestNG_WORKSPACE 執行測試案例
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite1">
<test name="test1">
<parameter name="myName" value="manisha"/>
<classes>
<class name="ParameterizedTest1" />
</classes>
</test>
</suite>
我們還可以定義引數在
級別。假設我們已經定義在兩個 和 級別myName,在這種情況下,常規的作用域規則適用。這意味著,任何類裡面 標籤將檢視值引數定義在 ,而testng.xml檔案中的類的其餘部分將看到定義在 中值
編譯使用javac的測試用例類。
javac ParameterizedTest1.java
現在,執行testng.xml,其中將執行parameterTest方法。TestNG的將試圖找到一個命名myName的第一
標籤的引數,然後,如果它不能找到它,它會搜尋包圍在的 標籤。
驗證輸出。
Parameterized value is : manisha
===============================================
Suite1
Total tests run: 1, Failures: 0, Skips: 0
===============================================
資料驅動(@DataProvider)
-
當你需要通過複雜的引數或引數需要建立從Java(複雜的物件,物件讀取屬性檔案或資料庫等..),在這種情況下,可以將引數傳遞使用資料提供者。資料提供者@DataProvider的批註的方法。
-
這個註解只有一個字串屬性:它的名字。如果不提供名稱,資料提供者的名稱會自動預設方法的名稱。資料提供者返回一個物件陣列。
讓我們看看下面的例子使用資料提供者。第一個例子是@DataProvider的使用Vector,String或Integer 作為引數,第二個例子是關於@DataProvider 的使用物件作為引數。
例項 1
在這裡 @DataProvider 通過整數和布林引數。
建立Java類
建立一個java類PrimeNumberChecker.java。這個類檢查,如果是素數。
public class PrimeNumberChecker {
public Boolean validate(final Integer primeNumber) {
for (int i = 2; i < (primeNumber / 2); i++) {
if (primeNumber % i == 0) {
return false;
}
}
return true;
}
}
建立測試案例類
- 建立一個Java測試類 ParamTestWithDataProvider1.java.
- 定義方法primeNumbers(),其定義為DataProvider 使用註釋。此方法返回的物件陣列的陣列。
- 測試方法testPrimeNumberChecker()新增到測試類中。此方法需要一個整數和布林值作為輸入引數。這個方法驗證,如果傳遞的引數是一個素數。
- 新增註釋 @Test(dataProvider = "test1") 到此方法。dataProvider的屬性被對映到"test1".
建立Java類檔名ParamTestWithDataProvider1.java
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class ParamTestWithDataProvider1 {
private PrimeNumberChecker primeNumberChecker;
@BeforeMethod
public void initialize() {
primeNumberChecker = new PrimeNumberChecker();
}
@DataProvider(name = "test1")
public static Object[][] primeNumbers() {
return new Object[][] { { 2, true }, { 6, false }, { 19, true },
{ 22, false }, { 23, true } };
}
// This test will run 4 times since we have 5 parameters defined
@Test(dataProvider = "test1")
public void testPrimeNumberChecker(Integer inputNumber,
Boolean expectedResult) {
System.out.println(inputNumber + " " + expectedResult);
Assert.assertEquals(expectedResult,
primeNumberChecker.validate(inputNumber));
}
}
建立 TESTNG.XML
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite1">
<test name="test1">
<classes>
<class name="ParamTestWithDataProvider1" />
</classes>
</test>
</suite>
執行testng.xml.
驗證輸出。
2 true
6 false
19 true
22 false
23 true
===============================================
Suite1
Total tests run: 5, Failures: 0, Skips: 0
===============================================
例項 2
在這裡,@DataProvider 傳遞物件作為引數。
建立Java類
建立一個Java類 Bean.java, 物件帶有 get/set 方法
public class Bean {
private String val;
private int i;
public Bean(String val, int i){
this.val=val;
this.i=i;
}
public String getVal() {
return val;
}
public void setVal(String val) {
this.val = val;
}
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}
建立測試案例類
- 建立一個Java測試類 ParamTestWithDataProvider2.java.
- 定義方法primeNumbers(),其定義為DataProvider使用註釋。此方法返回的物件陣列的陣列。
- 新增測試類中測試方法TestMethod()。此方法需要物件的bean作為引數。
- 新增註釋 @Test(dataProvider = "test1") 到此方法. dataProvider 屬性被對映到 "test1".
建立Java類檔名 ParamTestWithDataProvider2.java
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class ParamTestWithDataProvider2 {
@DataProvider(name = "test1")
public static Object[][] primeNumbers() {
return new Object[][] { { new Bean("hi I am the bean", 111) } };
}
@Test(dataProvider = "test1")
public void testMethod(Bean myBean) {
System.out.println(myBean.getVal() + " " + myBean.getI());
}
}
建立 TESTNG.XML
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite1">
<test name="test1">
<classes>
<class name="ParamTestWithDataProvider2" />
</classes>
</test>
</suite>
執行 testng.xml.
hi I am the bean 111
===============================================
Suite1
Total tests run: 1, Failures: 0, Skips: 0
===============================================
測試報告中自定義日誌(Reporter.log(“輸入自定義內容”)),例如:
@Test(groups = {"人"})
public void student(){
System.out.println("學生方法被呼叫");
Reporter.log("學生方法自定義日誌");
}
測試方法使用大全
TestNG預期異常測試
預期異常測試通過在@Test註解後加入預期的Exception來進行新增,範例如下所示:
@Test(expectedExceptions = ArithmeticException.class)
public void divisionWithException() {
int i = 1 / 0;
System.out.println("After division the value of i is :"+ i);
}
執行結果如下:
[RemoteTestNG] detected TestNG version 6.10.0
[TestNG] Running:
C:\Users\Administrator\AppData\Local\Temp\testng-eclipse--754789457\testng-customsuite.xml
PASSED: divisionWithException
===============================================
Default test
Tests run: 1, Failures: 0, Skips: 0
===============================================
===============================================
Default suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================
[TestNG] Time taken by org.testng.reporters.JUnitReportReporter@55d56113: 0 ms
[TestNG] Time taken by org.testng.reporters.SuiteHTMLReporter@1e127982: 0 ms
[TestNG] Time taken by org.testng.reporters.jq.Main@6e0e048a: 32 ms
[TestNG] Time taken by [FailedReporter passed=0 failed=0 skipped=0]: 0 ms
[TestNG] Time taken by org.testng.reporters.XMLReporter@43814d18: 0 ms
[TestNG] Time taken by org.testng.reporters.EmailableReporter2@6ebc05a6: 0 ms
TestNG忽略測試
有時候我們寫的用例沒準備好,或者該次測試不想執行此用例,那麼刪掉顯然不明智,那麼就可以通過註解@Test(enabled = false)來將其忽略掉,此用例就不會執行了,如下範例:
import org.testng.annotations.Test;
public class TestCase1 {
@Test(enabled=false)
public void TestNgLearn1() {
System.out.println("this is TestNG test case1");
}
@Test
public void TestNgLearn2() {
System.out.println("this is TestNG test case2");
}
}
執行結果:
this is TestNG test case2
PASSED: TestNgLearn2
TestNG超時測試
“超時”表示如果單元測試花費的時間超過指定的毫秒數,那麼TestNG將會中止它並將其標記為失敗。此項常用於效能測試。如下為一個範例:
import org.testng.annotations.Test;
public class TestCase1 {
@Test(timeOut = 5000) // time in mulliseconds
public void testThisShouldPass() throws InterruptedException {
Thread.sleep(4000);
}
@Test(timeOut = 1000)
public void testThisShouldFail() {
while (true){
// do nothing
}
}
}
結果如下:
PASSED: testThisShouldPass
FAILED: testThisShouldFail
org.testng.internal.thread.ThreadTimeoutException: Method com.demo.test.testng.TestCase1.testThisShouldFail() didn't finish within the time-out 1000
at com.demo.test.testng.TestCase1.testThisShouldFail(TestCase1.java:37)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:104)
at org.testng.internal.InvokeMethodRunnable.runOne(InvokeMethodRunnable.java:54)
at org.testng.internal.InvokeMethodRunnable.run(InvokeMethodRunnable.java:44)
at java.util.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)
未完待續
後續會進行詳細的介紹使用