在系统测试中使用Selenium时,使用Thread.Sleep的替代方法是什么?

我有一个使用Selenium的TestMethod如下:

[TestMethod] public void ShouldSendPasswordReminder() { // go to loginregister url _fireFoxWebDriver.Navigate().GoToUrl(UkPaBaseUrl + "loginregister.aspx"); Thread.Sleep(1000); // click the forgotten password _fireFoxWebDriver.FindElement(By.LinkText("Forgotten your password?")).Click(); Thread.Sleep(1000); // enter your email address _fireFoxWebDriver.FindElement(By.Id("PasswordResetRequest1_PasswordResetRequest_Username")) .SendKeys("username.lastname@domain.com"); Thread.Sleep(1000); // click submit _fireFoxWebDriver.FindElement(By.Id("PasswordResetRequest1_PasswordResetRequest_PasswordResetRequestSubmit")).Click(); Thread.Sleep(5000); // assert Assert.IsTrue(_fireFoxWebDriver.Url.Contains("ThankYou")); } 

正如你所看到的,我必须多次调用Thread.Sleep(因为页面可能需要一些时间来完成它由于javascript等所做的事情),因为Selenium似乎无法处理页面加载和延迟不同于WatiN。

这使代码相当丑陋而且不太可靠。

处理此类场景的更好方法是什么? 您是否也在测试中经常编写Thread.Sleep调用?

谢谢,

您可以使用managefunction设置FindElement()在失败前等待的基线时间:

 _fireFoxWebDriver.Manage() .Timeouts() .ImplicitlyWait(TimeSpan.FromSeconds(1000)); 

明确的等待。 根据官方文档( http://www.seleniumhq.org/docs/0 .. ),Thread.sleep()是显式等待的最坏情况。

在显式等待中,不等待最大时间结束,如果条件发生,如果在指定的最大时间结束之前发生该条件,则它会立即继续。 因此,必须等到最大时间(因为在指定的最大时间内没有发生条件)是显式等待的最坏情况。

我认为Thread.sleep()被认为是显式等待的最坏情况,因为对于Thread.sleep(),它必须等待指定为Thread.sleep()的参数的全部时间,然后继续进行。

您可能会想到为什么Thread.sleep()不是隐式等待。 我认为这是因为Thread.sleep()的效果仅在其写入的位置,如显式等待。 然而,隐式等待的效果是针对驱动程序实例的整个生命周期。

 **JAVA** WebDriver driver = new FirefoxDriver(); driver.get("http://somedomain/url_that_delays_loading"); WebElement myDynamicElement = (new WebDriverWait(driver, 10)).until(ExpectedConditions.presenceOfElementLocated(By.id("myDynamicElement"))); **C#** using (IWebDriver driver = new FirefoxDriver()) { driver.Url = "http://somedomain/url_that_delays_loading"; WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10)); IWebElement myDynamicElement = wait.Until(d => d.FindElement(By.Id("someDynamicElement"))); } 

在抛出TimeoutException之前等待最多10秒,或者如果它发现元素将在0-10秒内返回它。

我的示例代码,我的测试用例要求我等待最多10秒,之前我等待10秒,然后使用Thread.Sleep找到我的下一个元素。 现在我使用WebDriverWait,所以如果找到元素,它会加速我的日常活动并节省时间。

 using (IWebDriver driver = new ChromeDriver(options)) { TimeSpan t = TimeSpan.FromSeconds(10); WebDriverWait wait = new WebDriverWait(driver,t); try { driver.Navigate().GoToUrl("URL"); //IWebElement username = driver.FindElement(By.Name("loginfmt")); IWebElement username = wait.Until(ExpectedConditions.ElementIsVisible(By.Name("loginfmt"))); username.SendKeys(dictionaryItem); //Thread.Sleep(10000); Removed my Thread.Sleep and tested my wait.Until and vola it works awesome. IWebElement next = wait.Until(ExpectedConditions.ElementIsVisible(By.Id("idSIButton9"))); //IWebElement nextdriver.FindElement(By.Id("idSIButton9")); next.Click(); 

当我的脚本比我的应用程序更快时引入延迟的一般启发式方法是真正考虑我正在等待的内容。 在我看来,睡眠类型调用实际上只适用于我实际上等待时间过去的情况。 我正在测试自动超时的情况可能是有意义的,因为我实际上正在等待一段特定的时间。 但是,通常情况下,我正在等待其他事情发生 – 要加载的页面,要执行的javascript等等。在这些情况下,等待一段时间是一种简单的方法,似乎可以通过检查的更大复杂性我正在等待什么。 这有多个陷阱 – 你可能会放慢你的测试速度太多(例如,如果你的每个等待时间只需要200ms,那么现在甚至上面的简短片段需要额外的2.5秒(而且不需要调整5秒)第二次等到最后)。这可能看起来并不多,但随着你的套件越来越大,它会加起来。)当你搬到一台速度较慢的机器或者环境问题会减慢你的应用程序时会发生另一个陷阱 – 如果需要1.5秒在你点击忘记密码之前? 链接在一台机器上。 您的测试会失败,但可能仍然在您的应用程序的可接受的性能阈值范围内,因此您现在有一个错误的失败。 这通常只是通过简单地增加等待时间来处理,但这又导致了我再次提到的第一个陷阱。

为了摆脱这个循环,我发现在等待事情时尽可能具体是非常重要的。 Selenium提供了一个Wait类,可以用来等到满足特定条件。 我不知道.Net绑定是否包含它,但我会使用它们期待它。 在Ruby版本中,我们给Wait一个代码块 – 它可以查找元素的存在或我们需要检查的任何其他内容。 wait方法采用超时值和间隔值,然后每隔间隔秒运行一次,直到块返回true或超时时间已过。 设置这样的类允许您将超时值设置得足够高,以处理性能范围的低端,但不会导致等待的时间长于您在给定运行中实际需要的时间。