[轉]TestNG的多線程並行

來源:互聯網
上載者:User

標籤:href   sleep   date   避免   oca   other   get   ups   測試的   

前言

最近在做項目裡的自動化測試工作,使用的是TestNG測試架構,主要涉及的測試類型有介面測試以及基於業務實際情境的情境化測試。由於涉及的情境大多都是大資料的作業開發及執行(如MapReduce、Spark、Hql等任務的執行),而這些任務的執行都需要耗費較多的時間。舉一個普遍的例子,其中一條情境測試案例是:

  • 執行一個MapReduce作業,校正作業的執行結果和執行日誌。

對於一個最簡單的MR任務,如果YARN叢集資源充足,它的執行時間也要花上將近一分鐘的時間。更不用說當YARN叢集計算資源飽和時,任務還需要持續等待資源分派等。當測試迴歸用例集裡包含了大量此類的用例時,如果還用傳統的單線程執行方式,則一次自動化迴歸將會耗費大量的時間。

多線程並存執行

基於上述情境,我們可以考慮將自動化用例中相互之間沒有耦合關係,相對獨立的用例進行並存執行。如,我可以通過起不同的線程同時去執行不同的MR任務、Spark任務,每個線程各自負責跟蹤任務的執行情況。

此外,即使是單純的介面自動化測試,如果測試集裡包含了大量的用例時,我們也可以藉助於TestNG的多線程方式提高執行速度。

必須要指出的是,通過多線程執行用例時雖然可以大大提升用例的執行效率,但是我們在設計用例時也要考慮到這些用例是否適合并發執行,以及要注意多線程方式的通病:安全執行緒與共用變數的問題。建議是在測試代碼中,儘可能地避免使用共用變數。如果真的用到了,要慎用synchronized關鍵字來對共用變數進行加鎖同步。否則,難免你的用例執行時可能會出現不穩定的情景(經常聽到有人提到用例執行地不穩定,有時100%通過,有時只有90%通過,猜測可能有一部分原因也是這個導致的)。

TestNG中的多線程使用姿勢不同層級的並發

通常,在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。 實際上這種情況在實際中應用地並不多見,我們的測試案例往往放在一個suite中,如果真需要執行不同的suite,往往也是在不同的環境中去執行,屆時也自然而然會做一些其他的配置(如環境變數)更改,會有不同的進程去執行。因此這種方式不多贅述。

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">

它們的共同點都是最多起5個線程去同時執行不同的用例。 它們的區別如下:

  • tests層級:不同test tag下的用例可以在不同的線程執行,相同test tag下的用例只能在同一個線程中執行。
  • classs層級:不同class tag下的用例可以在不同的線程執行,相同class tag下的用例只能在同一個線程中執行。
  • methods層級:所有用例都可以在不同的線程去執行。

搞清楚並發的層級非常重要,可以幫我們合理地組織用例,比如將非安全執行緒的測試類別或group統一放到一個test中,這樣在並發的同時又可以保證這些類裡的用例是單線程執行。也可以根據需要設定class層級的並發,讓同一個測試類別裡的用例在同一個線程中執行。

並發時的依賴

實踐中,很多時候我們在測試類別中通過dependOnMethods/dependOnGroups方式,給很多測試方法的執行添加了依賴,以達到期望的執行順序。如果同時在運行testng時配置了methods層級並發執行,那麼這些測試方法在不同線程中執行,還會遵循依賴的執行順序嗎?答案是——YES。牛逼的TestNG就是能在多線程情況下依然遵循既定的用例執行順序去執行。

不同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" >
同一個方法的並發

有些時候,我們需要對一個測試案例,比如一個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)來並發執行測試資料。

範例程式碼如下:

package testng.parallel.test;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()));    }}

測試結果:

Start Time: 2017-03-11 14:10:43[ThreadUtil] Starting executor timeOut:0ms workers:5 threadPoolSize:2Current Thread Id: 14. Dataprovider number: 2Current Thread Id: 15. Dataprovider number: 2Current Thread Id: 12. Dataprovider number: 1Current Thread Id: 13. Dataprovider number: 1Current Thread Id: 16. Dataprovider number: 1Current Thread Id: 18. Dataprovider number: 1Current Thread Id: 17. Dataprovider number: 2Current Thread Id: 19. Dataprovider number: 2Current Thread Id: 21. Dataprovider number: 2Current Thread Id: 20. Dataprovider number: 1End Time: 2017-03-11 14:10:58
Other TestNG Tips

TestNG作為一個成熟的、業界廣泛使用的測試架構,自然有其存在的合理性。這邊再分享一些簡單有用的標籤,具體的使用姿勢大家可以自己去探索,官網有比較全的介紹,畢竟自己探索的才會印象深刻。

  1. groups/dependsOnGroups/dependsOnMethods ——設定用例間依賴
  2. dataProviderClass ——將dataprovider單獨放到一個專用的類中,實現測試代碼、dataprovider、測試資料分層。
  3. timeout ——設定用例的逾時時間(並發/非並發都可支援)
  4. alwaysRun ——某些依賴的用例失敗了,導致用例被跳過。對於一些為了保持環境乾淨而“掃尾”的測試類別,如果我們想強制執行可以使用此標籤。
  5. priority ——設定優先權,讓某些測試案例被更大機率優先執行。
  6. singleThreaded ——強制一個class類裡的用例在一個線程執行,忽視method層級並發
  7. preserve-order ——指定是否按照testng.xml中的既定用例順序執行用例
總結

在TestNG中使用多線程的方式並存執行測試案例可以有效提高用例的執行速度,而且TestNG對多線程提供了很好的支援,即使是菜鳥也可以方便地上手多線程。此外,TestNG預設會使用線程池的方式建立線程,減小了程式的開銷。

參考連結
  • TestNG Documentation

轉自:http://www.cnblogs.com/znicy/p/6534893.html

[轉]TestNG的多線程並行

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.