3

我有一个使用 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 调用?

谢谢,

4

3 回答 3

3

FindElement()您可以使用管理功能设置失败前要等待的基线时间:

_fireFoxWebDriver.Manage()
                 .Timeouts()
                 .ImplicitlyWait(TimeSpan.FromSeconds(1000));
于 2012-01-26T17:22:28.553 回答
2

显式等待。根据官方文档(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<IWebElement>(d => d.FindElement(By.Id("someDynamicElement")));
}

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

我的示例代码,我的测试用例希望我最多等待 10 秒,之前我在使用 Thread.Sleep 找到下一个元素之前等待了 10 秒。现在我使用 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();
于 2016-12-22T00:53:58.430 回答
0

当我的脚本比我的应用程序更快时引入延迟的一般启发式方法是真正考虑我在等待什么。在我看来,睡眠类型的调用实际上只适用于我实际上在等待时间过去的情况。在我测试自动超时的情况下,在其中调用 Thread.sleep 类型可能是有意义的,因为我实际上是在等待特定的时间过去。然而,通常,我正在等待其他事情发生——要加载的页面、要执行的 javascript 等等。在这些情况下,等待一段设定的时间似乎是一种简单的方法,似乎可以克服检查的潜在更大复杂性对于我真正在等待的东西。但是,这有多个陷阱-您可能会大大减慢测试速度(如果上面的每个等待时间只需要 200 毫秒,该怎么办,例如 - 现在即使是上面的简短片段也需要额外的 2.5 秒(这还没有调整最后的 5 秒等待)。这本身可能看起来并不多,但随着您的套件变得更大,它会增加。)当您移动到较慢的机器或环境因素会减慢您的应用程序时会发生另一个陷阱 - 如果您需要 1.5 秒才能单击忘记您的密码?在一台机器上链接。您的测试会失败,但这可能仍然在您的应用程序可接受的性能阈值之内,因此您现在有一个错误的失败。这通常通过简单地增加等待时间来解决,但这又回到了我再次提到的第一个陷阱。这本身可能看起来并不多,但随着您的套件变得更大,它会增加。)当您移动到较慢的机器或环境因素会减慢您的应用程序时会发生另一个陷阱 - 如果您需要 1.5 秒才能单击忘记您的密码?在一台机器上链接。您的测试会失败,但这可能仍然在您的应用程序可接受的性能阈值之内,因此您现在有一个错误的失败。这通常通过简单地增加等待时间来解决,但这又回到了我再次提到的第一个陷阱。这本身可能看起来并不多,但随着您的套件变得更大,它会增加。)当您移动到较慢的机器或环境因素会减慢您的应用程序时会发生另一个陷阱 - 如果您需要 1.5 秒才能单击忘记您的密码?在一台机器上链接。您的测试会失败,但这可能仍然在您的应用程序可接受的性能阈值之内,因此您现在有一个错误的失败。这通常通过简单地增加等待时间来解决,但这又回到了我再次提到的第一个陷阱。但这可能仍然在您的应用程序可接受的性能阈值范围内,因此您现在遇到了错误的失败。这通常通过简单地增加等待时间来解决,但这又回到了我再次提到的第一个陷阱。但这可能仍然在您的应用程序可接受的性能阈值范围内,因此您现在遇到了错误的失败。这通常通过简单地增加等待时间来解决,但这又回到了我再次提到的第一个陷阱。

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

于 2012-01-26T19:21:54.590 回答