2013-09-28 102 views
3

GlobalVariables類持有它們在我的框架中使用不同的變量其中之一是webdriver的實例:靜態的webdriver在Java實例同步

public class GlobalVariables 
     { 
     public static WebDriver driver; 
    //Some other static global variables required across my framework 
     public GlobalVariables(String propertiesFile) 
     { 
     initializeVariables(propertiesFile); 
     } 
     public void initializeVariables(String propertiesFile) 
     { 
     GlobalInitializer obj=new GlobalInitializer(); 
     obj.initialize(String propertiesFile); 
     } 
    } 

GlobalInitializer包含的方法來初始化所有GlobalVariables:

public class GlobalInitializer extends GlobalVariables 
{ 
public void initialize(String propertiesFile) 
{ 
    //Some logic to read properties file and based on the properties set in it, call other initialization methods to set the global variables. 
} 
public void initializeDriverInstance(String Browser) 
{ 
driver=new FireFoxDriver(); 
} 

//其他一些方法來初始化其他全局變量。 }

我有使用的驅動程序實例來獲得UI控件元素如許多GetElement類:

public class GetLabelElement extends GlobaleVariables 
{ 
public static WebElement getLabel(String someID) 
{ 
return driver.findElement(By.id(someId)); 
} 
//Similar methods to get other types of label elements. 
} 

public class GetTextBoxElement extends GlobaleVariables 
{ 
public static WebElement getTextBox(String someXpath) 
{ 
return driver.findElement(By.xpath(someXpath)); 
} 
//Similar methods to get other types of text box elements. 
} 

我有執行上的UI控件的一些行動(這班也使用全局變量其他類)例如:

public class GetLabelProperties extends GlobalVariables 
{ 
public static String getLabelText(WebElement element) 
{ 
return element.getText(); 
} 
} 

public class PerformAction extends GlobalVariables 
{ 
public static void setText(String textBoxName,String someText) 
{ 
driver.findElement(someLocator(textBoxName)).setText("someText"); 
} 
    //Some other methods which may or may not use the global variables to perform some action 
} 

TestNG中我的測試類是這樣的:

public class TestClass 
{ 
GlobalVariables globalObj=new GlobalVariables(String propertiesFile); 
@Test(priority=0) 
{ 
GlobalVariables.driver.get(someURL); 
//Some assertion. 
} 
@Test(priority=1) 
{ 
WebElement element=GetLabelElement.getLabel(someID); 
String labelName=GetLabelProperties.getLabelText(element); 
//Some assertion. 
} 
@Test(priority=2) 
{ 
WebElement element=GetTextBoxElement.getTextBox(someXpath); 
PerformAction.setText(element.getText(),someText); 
//Some assertion. 
} 
} 

我有類似的基於場景的多個測試類。 現在這個測試運行良好,如果我單獨運行它們。但是當我嘗試並行運行它們時,那​​麼這個測試在一些奇怪的時尚方面失敗了。在分析時,我發現它的靜態全局變量被每個測試初始化​​,從而使其他測試失敗。現在,我應該如何實現我的目標,在我的框架設計中進行微小的更改並行運行多個測試?我嘗試過搜索選項,並且我遇到了一些選項,即1)使用同步。 2)創建ThreadLocal實例(注意:我已經嘗試過這個解決方案,但仍然是相同的問題,測試相互混淆導致失敗,我已經將WebDriver實例標記爲ThreadLocal,並重寫ThreadLocal的initialValue方法來初始化驅動程序實例。不過我不確定我是否正確實施了它。)。現在我不確定如何在給定的情況下最好地實現這個解決方案中的任何一個。任何幫助表示讚賞。 TIA!

+0

首先,我喜歡簡單的「命名和目錄」模式共享全局變量,我不就像你的解決方案關於從全局變量類繼承而來的!所以通過一個界面(一個代理人),你可以在並行的情況下管理系統。 – 2013-09-28 17:37:22

回答

4

我已經找到了解決方案:ThreadLocal的使用是在一個巨大的多線程環境中進行測試的最佳解決方案。 代碼段在多線程環境中使用的webdriver:

public static ThreadLocal<WebDriver> driver; 
driver=new ThreadLocal<WebDriver>() 
       { 
        @Override 
        protected WebDriver initialValue() 
        { 
         return new FirefoxDriver(); //You can use other driver based on your requirement. 
        } 
       }; 

現在每次測試線程創建一個新的瀏覽器將打開。 ThreadLocal將確保每個線程只有一個靜態webdriver實例副本。 [注意:確保你的其他全局變量也是ThreadLocals。在我的情況下,他們並不是這就是爲什麼我遇到測試混亂問題]。一些額外的知識,我想分享,讓其他人可能會發現它的信息。在調用ThreadLocal.get()方法時,在ThreadLocal中,必須確保有一個規定來初始化本地線程,如initialValue()方法中所示,否則您可能會遇到空指針異常。感謝大家。

+0

你能展示一個更完整的代碼結構嗎?我似乎無法使用ThreadLocal進行工作。我喜歡這個主意,但是我對我不合適,並且對瀏覽器的實例進行了垃圾分類,這種方式遠不止於此。所以你:聲明靜態線程本地。並且在類的每個構造函數中,都會覆蓋initialValue()方法,對嗎?然後你通過threadLocalDriver.get()。findElement ...等地址來尋找webdriver? – Mercious

+0

我的設計是,我有一個基類,瀏覽器實例的初始化發生,然後由其他類擴展。所以在基類中,我通過重寫initialvalue或確保在調用get方法之前做到了這一點,我調用set方法來設置靜態threadlocal實例的值。 –

1

您收到此,因爲JVM如何處理靜態成員和方法。

你不能有一個靜態的webdriver對象,如果你要並行運行。

來源:自動化迴歸系統我實現了我的工作 - 我們這個問題。

2

如果要運行非平行,然後使用一個靜態的webdriver成員(或通過引用傳遞測試類之間共享的實例)是好的,因爲它是沒有關閉的webdriver的實例的好方法測試課程。如果你想,雖然平行,你需要有針對的webdriver使用靜態成員在這種情況下,每個線程等等的一個實例是走錯路。相反,您需要在調用測試用例類時創建或傳遞一個webdriver實例。

而且,你破壞了一個測試納入測試的每一步單獨的測試。也就是說非常不尋常的,我不明白你爲什麼要這麼做的原因。您可以通過將所有測試步驟保持在一個單獨的測試案例中,像人們通常所做的那樣,真正簡化您的測試。

+0

基於我的谷歌搜索和閱讀javadocs。我發現ThreadLocal可以用來實現這一點。現在糾正我,如果我錯了,ThreadLocal確保每個線程只有一個驅動程序實例在運行(即爲多個線程創建多個驅動程序(或瀏覽器)實例)。並且一個線程的驅動程序實例不會與另一個線程中運行的另一個實例混淆或混亂。對?請注意,我有一個非常巨大的應用程序進行測試,因此我將不得不按照我的上述設計,在粒度級別上幾乎分解了易用性 –

+0

個人而言,我不會使用ThreadLocal,因爲您的測試框架是做分叉和線程處理(例如TestNG,Maven Surefire,Gradle或其他)。如果你想親自編寫自己的線程處理和測試分支,那麼你很可能是因爲你不瞭解正確的Selenium設計模式,或者你是如此先進/知識淵博,以至於你有一個特殊情況需要它。 – djangofan

0

,你可以嘗試這樣的事情

公共類DriverManager的{

private static final ThreadLocal<WebDriver> threadLocal = new ThreadLocal<WebDriver>(); 

public static WebDriver getDriver() { 
    return threadLocal.get(); 
} 

public static void setDriver(WebDriver driver) { 
    threadLocal.set(driver); 
} 

public static void closeDriver() { 
    if (getDriver() != null) { 
     try { 
      getDriver().close(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     try { 
      getDriver().quit(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
    threadLocal.remove(); 
} 

}