既然是討論執行順序問題,那么用例肯定是批量執行的,批量執行的方法有mvn test、直接運行testng.xml文件,其中直接運行testng.xml文件的效果與pom文件中配置執行testng.xml效果是一樣,所以本次只討論mvn test 批量運行方式
一、用例准備
1、 測試用例
編寫一些測試用例,單純為了測試,內容只進行輸入,沒有任何邏輯。
public class FirstTest { @Test public void testFirst(){ System.err.println("first test"); } } |
2、pom文件配置
要使用mvn test方式批量運行用例,需要在pom文件中配置一下內容
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.19.1</version> </plugin> </plugins> </build> |
二、執行順序梳理
1、mvn test 默認順序
如果pom文件只是進行了上步驟的配置,那么執行mvn test,用例是多線程無序執行的,如果要按順序執行要配置為單線程,在<plugin>標簽內增加如下配置
<configuration> <forkCount>1</forkCount> <reuseForks>false</reuseForks> </configuration> |
再次執行mvn test,我們會發現用例是單線程,按一定順序執行的。但是是按照字母a-z的順序執行的,其實這個排序對我們來說用處不大,我們寫用例要求的是看名知意,不可能按照這個順序來寫。
2、priority 注解
testng提供了豐富的注解功能,priority標示用例執行的優先級,默認值為0,值越大優先級越低。比如:
public class FirstTest { @Test(priority = 2) public void testFirst(){ System.err.println("first test"); } } public class SecondTest { @Test public void testFirst(){ System.err.println("second test"); } } public class ThirdTest { @Test(priority = 1) public void testFirst() { System.err.println("third test"); } } 執行結果: second test third test first test |
該注解對同一個類的多個方法也是適用的,比如:
public class FirstTest { @Test(priority=2) public void testFirst2(){ System.err.println("first test2"); } @Test(priority=3) public void testFirst3(){ System.err.println("first test3"); } @Test(priority=1) public void testFirst(){ System.err.println("first test"); } } 執行結果: first test first test2 first test3 |
那么我們就會想如果每個類中都有多個方法,且優先級是不同的,那么執行順序又是怎么樣的?比如:
public class FirstTest { @Test(priority=2) public void testFirst2(){ System.err.println("first test2"); } @Test public void testFirst3(){ System.err.println("first test3"); } @Test(priority=1) public void testFirst(){ System.err.println("first test1"); } } public class SecondTest { @Test public void testFirst(){ System.err.println("second test"); } } public class ThirdTest { @Test(priority = 1) public void testFirst() { System.err.println("third test"); } @Test(priority = 2) public void testFirst2() { System.err.println("third test 2"); } } 運行結果: first test3 second test first test1 third test first test2 third test 2 |
這種情況我們從結果可以看出並沒有按照類的順序執行,而是按照priority設置的等級高低,去執行的類。那么這個問題的原因是什么?有沒有辦法類按照順序執行同時類中方法也按照順序執行?這個問題我們放到后面討論解決方法。
3、dependsOnGroups
public class FirstTest { @Test(dependsOnGroups={"second"}) public void testFirst(){ System.err.println("first test"); } } public class SecondTest { @Test(groups="second",dependsOnGroups={"third"}) public void testFirst(){ System.err.println("second test"); } public class ThirdTest { @Test(groups="third") public void testFirst() { System.err.println("third test"); } } 執行結果: third test second test first test |
同樣該方法適用於類的方法,比如:
public class FirstTest { @Test(dependsOnGroups={"first"},groups="second") public void testFirst2(){ System.err.println("first test2"); } @Test(groups="first") public void testFirst3(){ System.err.println("first test3"); } @Test(dependsOnGroups={"second"}) public void testFirst(){ System.err.println("first test1"); } } 執行結果: first test3 first test2 first test1 |
4、dependsOnMethods
該方法只適用於同一個類的不同方法間,不能跨類適用。舉例如:
public class Third10Test { @Test(dependsOnMethods = { "testFirst3" }) public void testFirst1() { System.err.println("third10 test1"); } @Test public void testFirst2() { System.err.println("third10 test2"); } @Test(dependsOnMethods = { "testFirst2" }) public void testFirst3() { System.err.println("third10 test3"); } } 執行結果: third10 test2 third10 test3 third10 test1 |
5、testng.xml
pom文件中在maven-surefire-plugin插件增加配置如下:
<configuration> <suiteXmlFiles> <suiteXmlFile>testng.xml</suiteXmlFile> </suiteXmlFiles> </configuration> |
testng.xml作為testng的靈魂,提供了很強大的配置功能,其它使用方式可以自己百度。本問只討論類型的執行順序問題。tesng.xml配置如下:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="Suite1" > <test name="Nopackage"> <classes> <class name="com.appiumforatk.SecondTest" /> <class name="com.appiumforatk.FirstTest" /> <class name="com.appiumforatk.ThirdTest" /> </classes> </test> </suite> |
執行mvn test 結果如下:
Second test
first test
third test
從結果可以看出,默認是按照順序執行。其實在suite和test標簽分別有preserve-order控制各自子標簽的執行順序,該值默認true。
如果我們把該值設置為false,可以看到用例不再按照配置的順序執行了。如下:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="Suite1" > <test name="Nopackage" preserve-order="false"> <classes > <class name="com.appiumforatk.SecondTest" /> <class name="com.appiumforatk.FirstTest" /> <class name="com.appiumforatk.ThirdTest" /> </classes> </test> </suite> |
執行mvn test命令,結果如下:
first test
Second test
third test
那么我們開始思考,如果testng.xml中設置了preserve-order= “true”,同時我們也設置了priority,那么執行順序會怎么樣?比如:我們只在SecondTest上加了priority=1,其它保持不變。
public class SecondTest { @Test public void testFirst(){ System.err.println("Second test"); } @Test(priority = 1) public void testFirst1(){ System.err.println("Second test1"); } } public class ThirdTest { @Test public void testFirst() { System.err.println("third test"); } @Test(priority = 1) public void testFirst1() { System.err.println("third test1"); } } |
mvn test執行結果如下:
Second test
first test
third test
Second test1
third test1
從結果可以看出同一priority優先級方法,按照配置的順序執行。也即priority的優先級>preserve-order.那么我們回到2中的問題,原因是因為priority是在testng開始的時候全部加載進去,如果想實現按順序執行完一個類的方法后,再執行另外一個類的方法,就要去改變方法的priority值,可以通過監聽的方式實現。代碼如下:
public class RePrioritizingListener implements IAnnotationTransformer { HashMap<Object, Integer> priorityMap = new HashMap<Object, Integer>(); Integer class_priorityCounter = 10000; Integer max_testpriorityLength = 4; @Override public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { Class<?> declaringClass = testMethod.getDeclaringClass(); Integer test_priority = annotation.getPriority(); Integer current_ClassPriority = priorityMap.get(declaringClass); // 如果類沒有設置過優先級,則進行設置。 if (current_ClassPriority == null) { current_ClassPriority = class_priorityCounter++; priorityMap.put(declaringClass, current_ClassPriority); } //獲取類中方法的優先級,如果小於四位數則左側補充0以達到四位數 String concatenatedPriority = test_priority.toString(); while (concatenatedPriority.length() < max_testpriorityLength) { concatenatedPriority = "0" + concatenatedPriority; } //把類的優先級和方法的優先級合並 concatenatedPriority = current_ClassPriority.toString() + concatenatedPriority; //重新設置方法的優先級 annotation.setPriority(Integer.parseInt(concatenatedPriority)); } } |
testng.xml配置如下:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="Suite1" > <test name="Nopackage" preserve-order="true"> <classes > <class name="com.appiumforatk.SecondTest" /> <class name="com.appiumforatk.FirstTest" /> <class name="com.appiumforatk.ThirdTest" /> </classes> </test> <listeners> //配置監聽 <listener class-name="com.appiumforatk.RePrioritizingListener"/> </listeners> </suite> |
mvn test執行命令結果如下:
Second test
Second test1
first test
third test
third test1
這個時候我們看到按照配置的順序執行class並且class中的方法也是按照priority優先級執行的。