2017-04-14 150 views
0

所以我創造了2個通用功能FindElementFindElements硒尋找元素

public class Find 
{ 
    public static IWebElement Element(IWebDriver driver, Func<IWebDriver, IWebElement> expectedCondtions, 
     By locator, IWebElement finder = null, int timeOutInSeconds = 120) 
    { 
     WebDriverWait webDriverWait = CreateWebDriverWait(driver, timeOutInSeconds); 
     webDriverWait.Until(expectedCondtions); 

     if (finder != null) 
      return finder.FindElement(locator); 
     return driver.FindElement(locator); 
    } 

    public static ReadOnlyCollection<IWebElement> Elements(IWebDriver driver, Func<IWebDriver, ReadOnlyCollection<IWebElement>> expectedCondtions, 
     By locator, IWebElement finder = null, int timeOutInSeconds = 120) 
    { 
     WebDriverWait webDriverWait = CreateWebDriverWait(driver, timeOutInSeconds); 
     webDriverWait.Until(expectedCondtions); 

     if (finder == null) 
      return driver.FindElements(locator); 
     return finder.FindElements(locator); 

    } 

    private static WebDriverWait CreateWebDriverWait(IWebDriver driver, int timeOutInSeconds) 
    { 
     WebDriverWait webDriverWait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeOutInSeconds)); 
     webDriverWait.IgnoreExceptionTypes(typeof(NoSuchElementException)); 
     return webDriverWait; 
    } 
} 

用法:

IWebElement element = 
    Find.Element(
    driver, 
    ExpectedConditions.ElementIsVisible(By.CssSelector("bla bla")), 
    By.CssSelector("bla bla")); 

正如你看到的我是把我的locator兩次,我function所以我的問題是有一種方法可以只發送一次?

回答

1

如果我理解你的意圖,那就是編寫一些通用函數來使代碼更清晰。這在概念上是一件好事,但我認爲在這種情況下它並沒有達到你所希望的。我看到許多人想要做這樣的事情。他們希望圍繞Selenium提供的簡單方法創建一個包裝,但最終他們沒有簡化代碼,使得代碼變得更加複雜,在調用堆棧中增加了另一層東西,可能引入了錯誤,並創建了專有任何使用你的代碼庫的人都必須學習API,而不是僅僅使用基本的Selenium命令。當每個元素都通過一個函數發現時,該函數引入的任何錯誤或間歇性問題都可以在套件中的每個腳本中看到。

一個簡單的比較:

使用您的Find方法

IWebElement e = Find.Element(Driver, ExpectedConditions.ElementToBeClickable(By.CssSelector("#checkboxes > input")), By.CssSelector("#checkboxes > input"), null, 10); 

硒唯一途徑

IWebElement e = new WebDriverWait(Driver, TimeSpan.FromSeconds(10)).Until(ExpectedConditions.ElementToBeClickable(By.CssSelector("#checkboxes > input"))); 

用你的方法是不是到底真乾淨。我會以Selenium-only的方式繼續前進,並且執行類似的操作來重複等待,使代碼變得更清潔。

WebDriverWait wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(10)); 
IWebElement e = wait.Until(ExpectedConditions.ElementToBeClickable(By.CssSelector("#checkboxes > input"))); 
IWebElement e2 = wait.Until(ExpectedConditions.ElementToBeClickable(By.Id("checkboxes"))); 

而且由於Until()返回元素,只是簡單地操作,如.Click()

wait.Until(ExpectedConditions.ElementToBeClickable(By.CssSelector("#checkboxes > input"))).Click(); 

如果您使用頁面對象模型(在一般情況下,你應該),你將存儲你的定位器然後像下面一樣使用它們,使代碼更加清潔。

wait.Until(ExpectedConditions.ElementToBeClickable(checkboxLocator)).Click(); 

話雖如此,我會重寫這些像這樣

public class Find 
{ 
    public static IWebElement Element(WebDriverWait wait, Func<IWebDriver, IWebElement> expectedCondition) 
    { 
     return wait.Until(expectedCondition); 
    } 
    public static IReadOnlyCollection<IWebElement> Elements(WebDriverWait wait, Func<IWebDriver, IReadOnlyCollection<IWebElement>> expectedCondition) 
    { 
     return wait.Until(expectedCondition); 
    } 
} 

Until()方法返回找到的元素(S),所以你可以只返回其省去了找東西兩倍的回報,消除了兩次發送定位器的需要。

我刪除了在方法中創建的WebDriverWait(),因爲您確實應該重用單個實例。我不瞭解你,但我通常不需要10個不同的等待時間,我可能會用一對夫婦。在你的測試腳本中聲明它們並將它們傳遞給它們。

我刪除了finder元素,因爲它不應該被需要。您可以使用CSS選擇器輕鬆創建一個查找子元素的定位器。

CreateWebDriverWait()中,您不需要忽略NoSuchElementException,它已經內置。因此,此功能可以降低到

private static WebDriverWait CreateWebDriverWait(IWebDriver driver, int timeOutInSeconds) 
{ 
    return new WebDriverWait(driver, TimeSpan.FromSeconds(timeOutInSeconds)); 
} 

它在這一點上,你要問自己爲什麼Find.CreateWebDriverWait()new WebDriverWait()更好?你通過編寫這個單獨的方法獲得了什麼?通過使用單獨的方法創建WebDriverWait,即使超時時間爲10秒,也會創建一個新實例,在Element()Elements()中尤其如此。所以,我從代碼中省略了它。

+0

這是非常全面的解釋,非常感謝。 – user979033