本系列所有代碼 https://github.com/zhangting85/simpleWebtest
本文將介紹一個(gè)Java+TestNG+Maven+Selenium的web自動(dòng)化測(cè)試腳本環(huán)境下selenium和testNG的多線程并發(fā)測(cè)試的實(shí)現(xiàn),并提供全部代碼。
?
這里我的多線程的執(zhí)行測(cè)試用例,目的首先是為了提高測(cè)試執(zhí)行速度,然后是為做分布式測(cè)試提供技術(shù)基礎(chǔ)。
?
testNG自帶了多線程機(jī)制,那么為什么要我們還要自己寫一些代碼呢?
因?yàn)閟elenium webdriver本身不是線程安全的。比如說,我直接在一個(gè)testNG的case里新建兩個(gè)webdriver,再做操作,他們就會(huì)沖突。然后其中一個(gè)會(huì)死掉。
如果我們直接用testNG的多線程,也會(huì)遇到類似的問題。
這里,我用thread local來解決線程安全問題:
?
在DriverManager類中,
ThreadLocal的泛型變量的聲明如下:
1 /** 2 * 每個(gè)DriverManager只管理一個(gè)driver,所以他是static的,但是我引入ThreadLocal來處理多線程 3 * shares the same web driver and use thread local to handle the multi-thread 4 */ 5 public static ThreadLocal<WebDriver> ThreadDriver= new ThreadLocal<WebDriver>() ;
之后是執(zhí)行case時(shí),要獲取一個(gè)可用的WebDriver對(duì)象來執(zhí)行測(cè)試,此時(shí)調(diào)用DriverManger.getDriver()方法來取得。
當(dāng)當(dāng)前進(jìn)程未綁定driver時(shí),創(chuàng)建一個(gè)driver,如果已綁定driver,則直接返回。所謂給當(dāng)前進(jìn)程綁定一個(gè)driver,使用的是 ThreadDriver.set(driver) 。
1 /** 2 * 如果當(dāng)前進(jìn)程沒有綁定driver,創(chuàng)建一個(gè)然后綁定上,如果已經(jīng)有了就直接返回 3 * create a driver for this thread if not exist. or return it directly 4 */ 5 public static WebDriver getDriver(){ 6 WebDriver driver= DriverManager.ThreadDriver.get(); 7 if (driver== null ){ 8 if (browserType.equals("firefox" )){ 9 driver = new EventFiringWebDriver( new FirefoxDriver()).register( new LogEventListener()); 10 ThreadDriver.set(driver); 11 // 找東西前等三秒wait 3 second for every find by 12 DriverManager.getDriver().manage().timeouts().implicitlyWait(3 , TimeUnit.SECONDS); 13 } 14 // 有需求的同學(xué)自己在這里添加IE等瀏覽器的支持 15 // you can add ie/chrome or other driver here 16 } 17 return driver; 18 }
?
這樣添加完之后,我們的webdriver已經(jīng)變成了線程安全的。
之后就可以執(zhí)行并發(fā)的測(cè)試,這里用了testng的dataprovider的多線程功能:

1 /** 2 * JD首頁上搜索一個(gè)商品 主要介紹定位某個(gè)商品名稱的N種寫法 3 * 這里用了DataProvider 4 * (不會(huì)用DataProvier不要說自己懂testNG) 5 */ 6 @Test(dataProvider="product_to_search" ) 7 public void searchProduct(String keyword) throws InterruptedException { 8 log.info("keyword="+ keyword); 9 String actual_procut_name= new JDHomepage().init().searchHeader.search(keyword).getProductNameByIndexMethodTwo(1 ); 10 log.info("actual_procut_name="+ actual_procut_name); 11 assert (actual_procut_name.contains(keyword)); 12 log.info("--------------------------------" ); 13 } 14 15 /** 16 * 用了DataProvider并且是并行的。但是這個(gè)是運(yùn)行不通過的。因?yàn)閃ebDriver不是線程安全的。 17 * 稍后我會(huì)再修復(fù)這個(gè)。。。暫時(shí)先這樣吧。 18 * 19 * 2014-4-20:更新了DriverManager,現(xiàn)在這個(gè)框架里的WebDriver是線程安全的了,所以這個(gè)腳本就可以并行執(zhí)行4個(gè)測(cè)試數(shù)據(jù)了。 20 * 詳見DriverManager類 21 * 22 */ 23 @DataProvider(name="product_to_search",parallel = true ) 24 public Iterator<Object[]> createData1() { 25 // 一個(gè)Array 26 String[] astringarray={"巧克力","餅","糕","蛋" }; 27 // 轉(zhuǎn)成一個(gè)String的List 28 List<String> lines= Arrays.asList(astringarray); 29 30 // 一個(gè)Object的空的List 31 List<Object[]> data = new ArrayList<Object[]> (); 32 33 // 往空List里放東西,然后返回 34 for (String line :lines ) 35 { 36 data.add( new Object[]{line}); // 加了一個(gè)FirefoxDriver進(jìn)去哦 37 } 38 return data.iterator(); 39 40 }
?
當(dāng)dataprovider設(shè)置了parallel參數(shù)為true時(shí),測(cè)試即會(huì)并發(fā)執(zhí)行。這里的真實(shí)并發(fā)數(shù)受到CPU內(nèi)核數(shù)限制。
具體代碼詳見我的github
?
另外,使用了這些代碼將webdriver和現(xiàn)成綁定,并使用testng提供的多線程功能后,這個(gè)測(cè)試框架下的測(cè)試用例變得可以簡(jiǎn)單得移植到selenium grid上,實(shí)現(xiàn)分布式測(cè)試。只需要再改動(dòng)一下啟動(dòng)driver的代碼。
下期再見。
selenium從入門到應(yīng)用 - 8,selenium+testNG實(shí)現(xiàn)多線程的并發(fā)測(cè)試
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
