1.TestNG的運行方式如下:
1 With a testng.xml file 直接run as test suite 2 With ant 使用ant 3 From the command line 從命令行 4 IDE 直接在IDE中執行
在IDEA中直接運行的時候,需要說明的是:可以運行一個測試類,也可以單獨運行一個測試的方法。
在IDEA里執行,只需要右鍵,點擊 Run xxx 即可。 如果是在某一個方法的代碼塊里右鍵,出現的是 Run methodName ,即只運行當前的方法; 如果是在類的代碼塊里右鍵,出現的是 Run className ,即運行當前類中的所有Test方法; 也可以創建testng.xml,右鍵出現的 Run path/testng.xml ,即運行該配置文件中需要運行的方法。
2.TestNG常見的注解:
注解 | 描述 |
@DataProvider | 為測試方法提供數據 |
@BeforeMethod | 在每個測試方法 前 執行 |
@AfterMethod | 在每個測試方法 后 執行 |
@BeforeClass | 被注釋的方法將在當前類的第一個測試方法調用前運行 |
@AfterClass | 被注釋的方法將在當前類的所有測試方法調用后運行 |
@BeforeGroups | 被配置的方法將在列表中的gourp前運行。這個方法保證在第一個屬於這些組的測試方法調用前立即執行 |
@BeforeTest | 被注釋的方法將在測試運行前運行 |
@AfterTest | 被注釋的方法將在測試運行后運行 |
@BeforeSuite | 被注釋的方法將在所有測試運行前運行 |
@AfterSuite | 被注釋的方法將在所有測試運行后運行 |
另外還有一些屬性,
alwaysRun:對於每個bufore方法(beforeSuite, beforeTest, beforeTestClass 和 beforeTestMethod, 但是不包括 beforeGroups):
如果設置為true,被配置的方法將總是運行而不管它屬於哪個組。
對於after方法(afterSuite, afterClass, ...): 如果設置為true,被配置的方法甚至在一個或多個先調用的方法失敗或被忽略時也將運行。
dependsOnGroups:這個方法依賴的組列表
dependsOnMethod:這個方法依賴的方法列表
enabled:這個類的方法是否激活
groups:這個類或方法所屬的分組列表
inheritGroups:如果設置為true,這個方法被屬於在類級別被@Test annotation指定的組例如:
@Test(enabled = false) //表示該測試用例不被執行 public Object runTest() { xxxxxx }
3.testNG.xml配置詳解:
testng.xml的基本格式可以在官網上查看,基本格式如下:
以下詳細XML結構規則
suite
--tests
----parameters
----groups
------definitions
------runs
----classes
--parameters
比較詳細的結構如下:
具體的元素說明:
參數 | 說明 | 使用方法 | 參數值 |
name | 必選項,<suite>的名字,將出現在reports里 | name="XXX" | suite名字 |
junit | 是否執行Junit模式(識別setup()等) | junit="true" | true和false,默認false |
verbose | 控制台輸出的詳細內容等級,0-10級(0無,10最詳細) | verbose="5" | 0到10 |
parallel | 是否在不同的線程並行進行測試,要與thread-count配套使用 | parallel="mehods" | 詳見表格下內容,默認false |
parent-module | 和Guice框架有關,只運行一次,創建一個parent injector給所有guice injectors | ||
guice-stage | 和Guice框架有關 | guice-stage="DEVELOPMENT" | DEVELOPMENT,PRODUCTION,TOOL,默認"DEVELOPMENT" |
configfailurepolicy | 測試失敗后是再次執行還是跳過,值skip和continue | configfailurepolicy="skip" | skip、continue,默認skip |
thread-count | 與parallel配套使用,線程池的大小,決定並行線程數量 | thread-count="10" | 整數,默認5 |
annotations | 獲取注解,值為javadoc時,使用JavaDoc的注釋;否則用JDK5注釋 | annotations="javadoc" | javadoc |
time-out | 設置parallel時,終止執行單元之前的等待時間(毫秒) | time-out="10000" | 整數,單位毫秒 |
skipfailedinvocationcounts | 是否跳過失敗的調用 | skipfailedinvocationcounts="true" | true和false,默認false |
data-provider-thread-count | 並發時data-provider的線程池數量 | data-provider-thread-count="5" | 整數 |
object-factory | 一個實現IObjectFactory接口的類,實例化測試對象 | object-factory="classname" | 類名 |
allow-return-values | 是否允許返回函數值 | all-return-values="true" | true和false |
preserve-order | 是否按照排序執行 | preserve-order="true" | true和false,默認true |
group-by-instances | 按照實例分組 | group-by-instances="true" | true和false,默認false |
parallel
<suite-files> <suite-file path="/path/suitefile1"></suite-file> </suite-files>
參數 | 說明 | 使用方法 | 參數值 |
name | test的名字,將出現在報告里 | name="testname" | test的名字 |
junit | 是否按照Junit模式運行 | junit="true" | true和false,默認false |
verbose | 控制台輸出的詳細內容等級,0-10級(0無,10最詳細),不在報告顯示 | verbose="5" | 0到10 |
parallel | 是否在不同的線程並行進行測試,要與thread-count配套使用 | parallel="mehods" | 與suite的parallel一致,默認false |
thread-count | 與parallel配套使用,線程池的大小,決定並行線程數量 | thread-count="10" | 整數,默認5 |
annotations | 獲取注解,值為javadoc時,使用JavaDoc的注釋;否則用JDK5注釋 | annotations="javadoc" | javadoc |
time-out | 設置parallel時,終止執行單元之前的等待時間(毫秒) | time-out="10000" | 整數,單位毫秒 |
enabled | 標記是否執行這個test | enabled="true" | true和false,默認true |
skipfailedinvocationcounts | 是否跳過失敗的調用 | skipfailedinvocationcounts="true" | true和false,默認false |
preserve-order | 是否按照排序執行,如果是true,將按照xml文件中的順序去執行 | preserve-order="true" | true和false,默認true |
allow-return-values | 是否允許返回函數值 | all-return-values="true" | true和false,默認false |
<method-selectors> <method-selector> <selector-class name="classname" priority="1"></selector-class> <script language="java"></script> (language還可以用beanshell等) </method-selector> </method-selectors>
<groups> <define name ="all"> <include name ="testgroup1"/> <exclude name ="testgroup2'/> </define> <run> <include name ="all"/> <include name ="testmethod1"/> <exclude name="testmethod2"/> </run> <dependencies> <group name ="group1" depends-on="goup2 group3"/> </dependencies> </groups>
<classes> <class name="要執行的class名"> <methods> <include name ="要執行的方法名"></include> </methods> </class> </classes>
<packages> <package name="packagename"/> <package name="packagename"> <include name="methodname"/> <exclude name="methodname"/> </package> </packages>
<listeners> <listener class-name="com.example.MyListener"/> <listener class-name="com.example.MyMehodIntercepor"/> </listeners>
(3)一個簡單的testng.xml文檔
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="Suite" parallel="classes" thread-count="3"> <test verbose="2" preserve-order="true" name="TestDebug"> <classes> <class name="com.hera.util.MathTest" /> </classes> </test> <!-- Test --> </suite> <!-- Suite -->
說明: suite定義一個測試套件,可以設置是否使用多線程,可包含多個測試用例或者測試group
parallel = classes 每個測試用例class級別多線程
thread-count =3 線程數為5,可同時執行3個case
preserve-order = true classes和methods按照配置中的順序執行,false為亂序執行。(If you want the classes and methods listed in this file to be run in an unpredictible order, set the preserve-order attribute to false)
parameter 標簽傳遞參數
4.TestNG參數化測試
<?xml version="1.0" encoding="UTF-8" ?>
<suite name = "testngframetest">
<parameter name="para" value="test_para1"/>
<test name="測試參數賦值">
<classes>
<parameters>
<parameter name="para1" value="test_para1"/>
<parameter name="para2" value="test_para2"/>
</parameters>
<class name = "paramer">
<methods>
<include name ="showparamer"></include>
</methods>
</class> </classes> </test> </suite>
import org.testng.annotations.Test; public class paramer { @Test(parameters ={"para1","para2"}) public void showparamer(String para11,String para22){ System.out.println("testng獲得的參數para1如下:"+para11); System.out.println("testng獲得的參數para2如下:"+para22);; } }
import org.testng.annotations.Optional; import org.testng.annotations.Test; public class paramer { @Test(parameters ={"para1","para2"}) public void showparamer(@Optional("test1") String para11, @Optional("test2") String para22){ System.out.println("testng獲得的參數para1如下:"+para11); System.out.println("testng獲得的參數para2如下:"+para22);; } }
public Object[][] dataprovide(){
return new Object[][]{{1,2,3},{3,2,1}};
}
@DataProvider(name = "dataprovider1",parallel = true) public Object[][] dataprovide(){ return new Object[][]{{1,2},{2,1}}; } @Test(dataProvider = "dataprovide") public void showDataprovide(int a,int b,Method c){ System.out.println("DataProvider獲得的參數para1如下:"+a); System.out.println("DataProvider獲得的參數para2如下:"+b);; System.out.println("DataProvider獲得的參數para2如下:"+c.getName()); }
5.Testng的並發詳解
5.1 不同級別的並發
通常,在TestNG的執行中,測試的級別由上至下可以分為suite -> test -> class -> method,箭頭的左邊元素跟右邊元素的關系是一對多的包含關系。
這里的test指的是testng.xml中的test tag,而不是測試類里的一個@Test。測試類里的一個@Test實際上對應這里的method。所以我們在使用@BeforeSuite、@BeforeTest、@BeforeClass、@BeforeMethod這些標簽的時候,它們的實際執行順序也是按照這個級別來的。
suite
一般情況下,一個testng.xml只包含一個suite。如果想起多個線程執行不同的suite,官方給出的方法是:通過命令行的方式來指定線程池的容量。
java org.testng.TestNG -suitethreadpoolsize 3 testng1.xml testng2.xml testng3.xml
即可通過三個線程來分別執行testng1.xml、testng2.xml、testng3.xml。
test, class, method
test,class,method級別的並發,可以通過在testng.xml中的suite tag下設置,如:
<suite name="Testng Parallel Test" parallel="tests" thread-count="5"> <suite name="Testng Parallel Test" parallel="classes" thread-count="5"> <suite name="Testng Parallel Test" parallel="methods" thread-count="5">
它們的區別如下:
- tests級別:不同test tag下的用例可以在不同的線程執行,相同test tag下的用例只能在同一個線程中執行。
- classs級別:不同class tag下的用例可以在不同的線程執行,相同class tag下的用例只能在同一個線程中執行。
- methods級別:所有用例都可以在不同的線程去執行。
5.2 不同dataprovider的並發
在使用TestNG做自動化測試時,基本上大家都會使用dataprovider來管理一個用例的不同測試數據。而上述在testng.xml中修改suite標簽的方法,並不適用於dataprovider多組測試數據之間的並發。
執行時會發現,一個dp中的多組數據依然是順序執行。解決方式是:在@DataProvider中添加parallel=true。
import org.testng.annotations.DataProvider; import testdata.ScenarioTestData; public class ScenarioDataProvider { @DataProvider(name = "hadoopTest", parallel=true) public static Object [][] hadoopTest(){ return new Object[][]{ ScenarioTestData.hadoopMain, ScenarioTestData.hadoopRun, ScenarioTestData.hadoopDeliverProps }; } @DataProvider(name = "sparkTest", parallel=true) public static Object [][] sparkTest(){ return new Object[][]{ ScenarioTestData.spark_java_version_default, ScenarioTestData.spark_java_version_162, ScenarioTestData.spark_java_version_200, ScenarioTestData.spark_python }; } @DataProvider(name = "sqoopTest", parallel=true) public static Object [][] sqoopTest(){ return new Object[][]{ ScenarioTestData.sqoop_mysql2hive, ScenarioTestData.sqoop_mysql2hdfs }; } }
/***
默認情況下,dp並行執行的線程池容量為10,如果要更改並發的數量,也可以在suite tag下指定參數data-provider-thread-count:
***/
<suite name="Testng Parallel Test" parallel="methods" thread-count="5" data-provider-thread-count="20" >
5.3 同一個方法的並發
有些時候,我們需要對一個測試用例,比如一個http接口,執行並發測試,即一個接口的反復調用。TestNG中也提供了優雅的支持方式,在@Test標簽中指定threadPoolSize和invocationCount。
@Test(enabled=true, dataProvider="testdp", threadPoolSize=5, invocationCount=10)
- threadPoolSize表明用於調用該方法的線程池容量,該例就是同時起5個線程並行執行該方法;
- invocationCount表示該方法總計需要被執行的次數。該例子中5個線程同時執行,當總計執行次數達到10次時,停止。
注意,該線程池與dp的並發線程池是兩個獨立的線程池。這里的線程池是用於起多個method,而每個method的測試數據由dp提供,
如果這邊dp里有3組數據,那么實際上10次執行,每次都會調3次接口,這個接口被調用的總次數是10*3=30次。
threadPoolSize指定的5個線程中,每個線程單獨去調method時,用到的dp如果也是支持並發執行的話,會創建一個新的線程池(dpThreadPool)來並發執行測試數據。
import java.text.SimpleDateFormat; import java.util.Date; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class TestClass1 { private SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//設置日期格式 @BeforeClass public void beforeClass(){ System.out.println("Start Time: " + df.format(new Date())); } @Test(enabled=true, dataProvider="testdp", threadPoolSize=2, invocationCount=5) public void test(String dpNumber) throws InterruptedException{ System.out.println("Current Thread Id: " + Thread.currentThread().getId() + ". Dataprovider number: "+ dpNumber); Thread.sleep(5000); } @DataProvider(name = "testdp", parallel = true) public static Object[][]testdp(){ return new Object[][]{ {"1"}, {"2"} }; } @AfterClass public void afterClass(){ System.out.println("End Time: " + df.format(new Date())); } }
原文:https://www.cnblogs.com/Ronaldo-HD/p/9235210.html