TestNG簡介
Testng是一套開源測試框架,是從Junit繼承而來,testng意為test next generation
創建maven項目,添加依賴
<dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>6.14.3</version> <scope>test</scope> </dependency>
常用注解
@BeforeSuite / @AfterSuite
@BeforeTest / @AfterTest
@BeforeClass / @AfterClass,在類運行之前/后運行
@BeforeMethod / @AfterMethod,在測試方法之前/后運行
package com.qzcsbj; import org.testng.annotations.*; import org.testng.annotations.Test; /** * @描述 : <...> * @博客 : www.cnblogs.com/uncleyong * @微信 : ren168632201 */ public class TestAnnotation { @Test public void test(){ System.out.println("TestAnnotation.test"); System.out.println("線程ID:" + Thread.currentThread().getId()); } @Test public void test2(){ System.out.println("TestAnnotation.test2"); } @BeforeMethod public void beforeMethodTest(){ System.out.println("TestAnnotation.beforeMethodTest"); } @AfterMethod public void afterMethodTest(){ System.out.println("TestAnnotation.afterMethodTest"); } @BeforeClass public void beforeClassTest(){ System.out.println("TestAnnotation.beforeClassTest"); } @AfterClass public void afterClassTest(){ System.out.println("TestAnnotation.afterClassTest"); } @BeforeSuite public void beforeSuiteTest(){ System.out.println("TestAnnotation.beforeSuiteTest"); } @AfterSuite public void afterSuiteTest(){ System.out.println("TestAnnotation.afterSuiteTest"); } }
輸出結果:
TestAnnotation.beforeSuiteTest TestAnnotation.beforeClassTest TestAnnotation.beforeMethodTest TestAnnotation.test 線程ID:1 TestAnnotation.afterMethodTest TestAnnotation.beforeMethodTest TestAnnotation.test2 TestAnnotation.afterMethodTest TestAnnotation.afterClassTest TestAnnotation.afterSuiteTest
安裝插件Create TestNG XML
搜索:Create TestNG XML
安裝
重啟后
創建xml文件
在resources下創建suite.xml,文件名隨意,只要內容符合要求就可以了
suite:套件,包含一個或多個test
test:測試集,包含一個或多個classes
classes:測試類集合,包含一個或多個class
class:測試類,包含一個或多個方法
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="All Test Suite"> <!--<test verbose="2" preserve-order="true" name="test">--> <test name="test"> <classes> <class name="com.qzcsbj.TestAnnotation"/> </classes> </test> <test name="test2"> <classes> <class name="com.qzcsbj.TestAnnotationB"> <methods> <include name="testb"/> <!--指定要運行的方法--> </methods> </class> </classes> </test> </suite>
套件測試
第一個類
package com.qzcsbj; import org.testng.annotations.*; import org.testng.annotations.Test; /** * @描述 : <...> * @博客 : www.cnblogs.com/uncleyong * @微信 : ren168632201 */ public class TestAnnotation { @Test public void test(){ System.out.println("TestAnnotation.test"); System.out.println("線程ID:" + Thread.currentThread().getId()); } @Test public void test2(){ System.out.println("TestAnnotation.test2"); } @BeforeMethod public void beforeMethodTest(){ System.out.println("TestAnnotation.beforeMethodTest"); } @AfterMethod public void afterMethodTest(){ System.out.println("TestAnnotation.afterMethodTest"); } @BeforeClass public void beforeClassTest(){ System.out.println("TestAnnotation.beforeClassTest"); } @AfterClass public void afterClassTest(){ System.out.println("TestAnnotation.afterClassTest"); } @BeforeSuite public void beforeSuiteTest(){ System.out.println("TestAnnotation.beforeSuiteTest"); } @AfterSuite public void afterSuiteTest(){ System.out.println("TestAnnotation.afterSuiteTest"); } }
第二個類
package com.qzcsbj; import org.testng.annotations.*; import org.testng.annotations.Test; /** * @描述 : <...> * @博客 : www.cnblogs.com/uncleyong * @微信 : ren168632201 */ public class TestAnnotationB { @Test public void testb(){ System.out.println("TestAnnotation.testb=="); System.out.println("線程ID:" + Thread.currentThread().getId()); } @Test public void testb2(){ System.out.println("TestAnnotationB.testb2=="); } @BeforeMethod public void beforeMethodTestb(){ System.out.println("TestAnnotationB.beforeMethodTestb=="); } @AfterMethod public void afterMethodTestb(){ System.out.println("TestAnnotationB.afterMethodTestb=="); } @BeforeClass public void beforeClassTestb(){ System.out.println("TestAnnotationB.beforeClassTestb=="); } @AfterClass public void afterClassTestb(){ System.out.println("TestAnnotationB.afterClassTestb=="); } @BeforeSuite public void beforeSuiteTestb(){ System.out.println("TestAnnotationB.beforeSuiteTestb=="); } @AfterSuite public void afterSuiteTestb(){ System.out.println("TestAnnotationB.afterSuiteTestb=="); } }
輸出結果:
TestAnnotation.beforeSuiteTest TestAnnotationB.beforeSuiteTestb== TestAnnotation.beforeClassTest TestAnnotation.beforeMethodTest TestAnnotation.test 線程ID:1 TestAnnotation.afterMethodTest TestAnnotation.beforeMethodTest TestAnnotation.test2 TestAnnotation.afterMethodTest TestAnnotation.afterClassTest TestAnnotationB.beforeClassTestb== TestAnnotationB.beforeMethodTestb== TestAnnotation.testb== 線程ID:1 TestAnnotationB.afterMethodTestb== TestAnnotationB.afterClassTestb== TestAnnotation.afterSuiteTest TestAnnotationB.afterSuiteTestb==
忽略測試
測試過程中,問題還沒解決,可以先忽略,也就是不執行此方法
package com.qzcsbj; import org.testng.annotations.Test; /** * @博客 : www.cnblogs.com/uncleyong * @微信 : ren168632201 * @描述 : <...> */ public class TestIgnore { @Test public void testa(){ System.out.println("TestIgnore.testa"); } @Test(enabled = true) public void testb(){ System.out.println("TestIgnore.testb"); } @Test(enabled = false) public void testc(){ System.out.println("TestIgnore.testc"); } }
運行結果:
TestIgnore.testa TestIgnore.testb
分組測試
場景︰只想執行個別或者某一部分的測試用例
package com.qzcsbj; import org.testng.annotations.AfterGroups; import org.testng.annotations.BeforeGroups; import org.testng.annotations.Test; /** * @博客 : www.cnblogs.com/uncleyong * @微信 : ren168632201 * @描述 : <...> */ public class TestGroups { @Test(groups = "login") public void testa(){ System.out.println("TestIgnore.testa"); } @Test(groups = "submitOrder") public void testb(){ System.out.println("TestIgnore.testb"); } @Test(groups = "submitOrder") public void testc(){ System.out.println("TestIgnore.testc"); } @BeforeGroups("submitOrder") public void testBeforeGroups(){ System.out.println("TestGroups.testBeforeGroups"); } @AfterGroups("submitOrder") public void testAfterGroup(){ System.out.println("TestGroups.testAfterGroup"); } }
輸出結果:
TestIgnore.testa TestGroups.testBeforeGroups TestIgnore.testb TestIgnore.testc TestGroups.testAfterGroup
xml方式
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="All Test Suite"> <!--<test verbose="2" preserve-order="true" name="test">--> <test name="test"> <!--test必須有name屬性--> <groups> <run> <include name="submitOrder"/> </run> </groups> <classes> <class name="com.qzcsbj.TestGroups"/> </classes> </test> </suite>
輸出結果:
TestGroups.testBeforeGroups TestIgnore.testb TestIgnore.testc TestGroups.testAfterGroup
依賴測試
字符串數組,默認是空
dependsOnMethods和BeforeMethod的區別是: BeforeMethod是每個方法前都要執行,而dependsOnMethods只是依賴的方法前執行
package com.qzcsbj; import org.testng.annotations.Test; /** * @博客 : www.cnblogs.com/uncleyong * @微信 : ren168632201 * @描述 : <...> */ public class TestDepend { @Test(dependsOnMethods = {"test2"}) public void test(){ System.out.println("TestAnnotation.test"); } @Test public void test2(){ System.out.println("TestAnnotation.test2"); } }
運行結果:
TestAnnotation.test2 TestAnnotation.test
如果被依賴方法執行失敗,有依賴關系的方法不會被執行;
應用場景,登錄失敗,就不能進行下單等操作
package com.qzcsbj; import org.testng.annotations.Test; /** * @博客 : www.cnblogs.com/uncleyong * @微信 : ren168632201 * @描述 : <...> */ public class TestDepend { @Test(dependsOnMethods = {"test2"}) public void test(){ System.out.println("TestAnnotation.test"); } @Test public void test2(){ System.out.println("TestAnnotation.test2"); throw new RuntimeException(); // 拋出一個異常 } }
運行結果:
TestAnnotation.test2 java.lang.RuntimeException at com.qzcsbj.TestDepend.test2(TestDepend.java:19) 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:124) at org.testng.internal.Invoker.invokeMethod(Invoker.java:583) at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:719) at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:989) at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125) at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109) at org.testng.TestRunner.privateRun(TestRunner.java:648) at org.testng.TestRunner.run(TestRunner.java:505) at org.testng.SuiteRunner.runTest(SuiteRunner.java:455) at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:450) at org.testng.SuiteRunner.privateRun(SuiteRunner.java:415) at org.testng.SuiteRunner.run(SuiteRunner.java:364) at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52) at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:84) at org.testng.TestNG.runSuitesSequentially(TestNG.java:1208) at org.testng.TestNG.runSuitesLocally(TestNG.java:1137) at org.testng.TestNG.runSuites(TestNG.java:1049) at org.testng.TestNG.run(TestNG.java:1017) at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:72) at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:123)
超時
timeout屬性的單位為毫秒。
package com.qzcsbj; import org.testng.annotations.Test; /** * @博客 : www.cnblogs.com/uncleyong * @微信 : ren168632201 * @描述 : <...> */ public class TestTimeOut { @Test(timeOut = 1000) // 單位為毫秒值,期望在1秒內得到結果 public void test() throws InterruptedException { System.out.println("TestTimeOut.test"); Thread.sleep(500); } @Test(timeOut = 1000) public void test2() throws InterruptedException { System.out.println("TestTimeOut.test2"); for (int i = 10; i > 0; i--) { Thread.sleep(101); System.out.println(i); } System.out.println("執行結束。"); } }
輸出結果:
TestTimeOut.test2 10 9 8 7 6 5 4 3 2 org.testng.internal.thread.ThreadTimeoutException: Method com.qzcsbj.TestTimeOut.test2() didn't finish within the time-out 1000 at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.signalAll(AbstractQueuedSynchronizer.java:1953) at java.util.concurrent.ThreadPoolExecutor.tryTerminate(ThreadPoolExecutor.java:716) at java.util.concurrent.ThreadPoolExecutor.processWorkerExit(ThreadPoolExecutor.java:1014) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)
斷言
package com.qzcsbj; /** * @博客 : www.cnblogs.com/uncleyong * @微信 : ren168632201 * @描述 : <...> */ public class Add { public int sum(int a, int b){ return a+b; } }
package com.qzcsbj; import org.testng.Assert; import org.testng.annotations.Test; public class MyTest { @Test public void test(){ Add add = new Add(); int actual = add.sum(1, 2); int expect = 2; Assert.assertEquals(actual,expect); } }
參數化(數據驅動測試)
兩種方式向測試方法傳遞參數:
利用testng.xml定義parameter
利用DataProviders
xml文件參數化
package com.qzcsbj; import org.testng.annotations.Parameters; import org.testng.annotations.Test; /** * @博客 : www.cnblogs.com/uncleyong * @微信 : ren168632201 * @描述 : <...> */ public class TestParameter { @Test @Parameters({"name","id"}) public void test(String name, int id){ System.out.println("name=" + name + ", id=" + id); } }
xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="All Test Suite"> <!--<test verbose="2" preserve-order="true" name="test">--> <test name="test"> <!--test必須有name屬性--> <classes> <class name="com.qzcsbj.TestParameter"> <parameter name="name" value="qzcsbj"/> <parameter name="id" value="1"/> </class> </classes> </test> </suite>
運行結果:
name=qzcsbj, id=1
DataProvider參數化
代碼和數據未分離
package com.qzcsbj; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * @博客 : www.cnblogs.com/uncleyong * @微信 : ren168632201 * @描述 : <...> */ public class TestDataProvider { @Test(dataProvider="data") // 和下面的name對應起來 public void testDataProvider(String name, int id){ System.out.println("name=" + name + ", id=" + id); } @DataProvider(name = "data") // 如果沒有指定name,上面就寫下面的方法名:providerData public Object[][] providerData(){ Object[][] datas = new Object[][]{ {"zhangsan",1001}, {"lisi",1002}, {"wangwu",1003} }; return datas; } }
運行結果:
name=zhangsan, id=1001 name=lisi, id=1002 name=wangwu, id=1003
代碼和數據分離,數據存放在excel中
sheet名為data
ExcelUtil.java
package com.qzcsbj; import org.apache.poi.ss.usermodel.*; import java.io.File; import java.io.IOException; import java.util.Arrays; /** * @公眾號 : 全棧測試筆記 * @博客 : www.cnblogs.com/uncleyong * @微信 : ren168632201 * @描述 : <> */ public class ExcelUtil { // 方法也可以根據情況定義更多參數,比如讀取excel的列范圍 public static Object[][] getdataFromExcel(String excelPath){ Object[][] datas = null; try { // 獲取workbook對象 Workbook workbook = WorkbookFactory.create(new File(excelPath)); // 獲取sheet對象 Sheet sheet = workbook.getSheet("data"); datas = new Object[4][2]; // 獲取行 for (int i = 1; i < 5; i++) { Row row = sheet.getRow(i); // 獲取列 for (int j=0; j<=1;j++){ Cell cell = row.getCell(j); cell.setCellType(CellType.STRING); String value = cell.getStringCellValue(); datas[i-1][j] = value; } } } catch (IOException e) { e.printStackTrace(); } return datas; } public static void main(String[] args) { String excelPath = "E:\\case.xlsx"; Object[][] datas = getdataFromExcel(excelPath); for (Object[] data : datas) { System.out.println(Arrays.toString(data)); } } }
上面讀取到的數據
LoginCase.java
package com.qzcsbj; import com.qzcsbj.HttpPostRequest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.util.HashMap; /** * @博客 : www.cnblogs.com/uncleyong * @微信 : ren168632201 * @描述 : <...> */ public class LoginCase { @Test(dataProvider = "datasFromExcel") // 多條數據,且數據和代碼分離 public void test(String username, String password){ String url = "http://127.0.0.1:9999/login"; HashMap<String, String> params = new HashMap<String, String>(); params.put("username", username); params.put("password", password); String res = HttpPostRequest.postRequest(url, params); System.out.println("入參:username=" + username + ", password=" + password); System.out.println("響應:" + res); System.out.println("============================\n"); } @DataProvider(name = "datasFromExcel") public Object[][] datasFromExcel(){ Object[][] datas = ExcelUtil.getdataFromExcel("E:\\case.xlsx"); return datas; } }
進一步優化
每行數據封裝到對象或者map,返回:Iterator<Object[]>
每個一維里面是一個對象或者map
原文:https://www.cnblogs.com/uncleyong/p/15867747.html