在系统测试中使用 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("[email protected]");
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 调用?
谢谢,
I have a TestMethod using Selenium as below:
[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("[email protected]");
Thread.Sleep(1000);
// click submit
_fireFoxWebDriver.FindElement(By.Id("PasswordResetRequest1_PasswordResetRequest_PasswordResetRequestSubmit")).Click();
Thread.Sleep(5000);
// assert
Assert.IsTrue(_fireFoxWebDriver.Url.Contains("ThankYou"));
}
As you can see, I'd have to call Thread.Sleep many times (because the page might take some time to finish what it does due to javascript, etc) almost after each action because Selenium doesn't seem to be able to handle page loads and delays unlike WatiN.
This makes the code rather ugly and not very much reliable.
What's the better way to handle such scenarios? Do you write frequent Thread.Sleep calls in your tests as well?
Thanks,
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您可以使用管理功能来设置
FindElement()
在失败之前等待的基线时间:You could use the manage functionality to set the base line time you want
FindElement()
to wait for before failing:显式等待。
根据官方文档(http://www.seleniumhq.org/docs/0...), Thread.sleep() 是显式等待的最坏情况。
在显式等待中,如果条件在指定的最大时间结束之前发生,则无需等待最长时间结束,只要条件发生,它就会继续执行。因此,必须等到最大时间(因为在指定的最大时间内条件没有发生)是显式等待的最坏情况。
我认为 Thread.sleep() 被认为是显式等待的最坏情况,因为对于 Thread.sleep() 来说,它必须等待 Thread.sleep() 参数指定的完整时间,然后才能继续进行。
您可能会想为什么 Thread.sleep() 不是隐式等待。我认为这是因为 Thread.sleep() 的效果仅在写入它的地方,就像显式等待一样。然而,隐式等待的影响是在驱动程序实例的整个生命周期内。
在抛出 TimeoutException 之前最多等待 10 秒,或者如果找到该元素将在 0 - 10 秒内返回它。
我的示例代码、我的测试用例要求我等待最多 10 秒,之前我等待 10 秒才使用 Thread.Sleep 找到下一个元素。现在我使用 WebDriverWait,因此如果找到该元素,它就会继续,这加快了我的日常活动并节省了时间。
Explicit wait.
According to official documentation (http://www.seleniumhq.org/docs/0...), Thread.sleep() is the worst case of explicit wait.
In explicit wait, without waiting for the maximum time to get over, it proceeds as soon as the condition occurs, if that condition occurs before the specified maximum time gets over. Hence having to wait till the maximum time (because the condition did not occur during the specified maximum time) is the worst case of explicit wait.
I think Thread.sleep() is considered as the worst case of explicit wait because, for Thread.sleep(), it has to wait for the full time specified as the argument of Thread.sleep(), before proceeding further.
You may think why Thread.sleep() isn't implicit wait. I think that is because effect of Thread.sleep() is only at the place where it is written, like explicit wait. Effect of implicit wait however, is for the entire lifetime of the driver instance.
This waits up to 10 seconds before throwing a TimeoutException or if it finds the element will return it in 0 - 10 seconds.
My sample code, my test case wanted me to wait for a maximum of 10 seconds, earlier I was waiting for 10 seconds before finding my next element using Thread.Sleep. Now I use the the WebDriverWait so if the element is found it proceeds, this speeds up my day to day activities and also saves time.
当我的脚本比我的应用程序更快时,我对引入延迟的一般启发是真正考虑我在等待什么。在我看来,睡眠类型的调用实际上只适用于我实际上正在等待时间流逝的情况。在我测试自动超时的情况下,在其中进行 Thread.sleep 类型调用可能是有意义的,因为我实际上正在等待特定的时间过去。然而,通常情况下,我会等待其他事情发生——要加载的页面、要执行的 JavaScript 等。在这些情况下,等待一段时间似乎是一种简单的方法,可以克服潜在的更复杂的检查为了我真正在等待的东西。但这有多个陷阱 - 你可能会减慢你的测试速度(例如,如果上面的每个等待只需要 200 毫秒怎么办) - 现在即使上面的简短片段也需要额外的 2.5 秒(并且这是没有调整 5最后第二次等待)。这本身看起来并不多,但随着你的套件变得越来越大,它就会增加。)当你移动到较慢的机器或环境因素减慢你的应用程序时,就会出现另一个陷阱 - 如果需要 1.5 会怎么样?几秒钟后,您可以单击忘记密码?链接在一台机器上。您的测试将失败,但这可能仍然在您的应用程序可接受的性能阈值内,因此您现在有一个错误的失败。通常可以通过简单地增加等待时间来解决这个问题,但这又会导致我再次提到的第一个陷阱。
为了打破这个循环,我发现在等待事情时尽可能具体是非常重要的。 Selenium 提供了一个 Wait 类,可用于等待直到满足特定条件。我不知道 .Net 绑定是否包含它,但我会期待它的使用。在 Ruby 版本中,我们给 Wait 一个代码块 - 它可以查找元素是否存在或我们需要检查的任何其他内容。 wait 方法采用超时值和间隔值,然后每隔间隔秒运行该块,直到该块返回 true 或超时期限已过。设置这样的类允许您将超时值设置得足够高,以处理性能范围的低端,但不会招致等待时间比给定运行中实际需要的时间长得多的损失。
My general heuristic on introducing delays when my script gets faster than my app is to really think about what I'm waiting for. In my opinion, sleep type calls are really only appropriate in cases where I'm actually waiting for time to elapse. A case where I was testing an automatic timeout might make sense to have a Thread.sleep type call in it, because I'm actually waiting for a specific amount of time to elapse. Usually, however, I'm waiting for other things to occur - pages to load, javascript to execute, etc. In these cases, waiting for a set period of time is an easy way to seem to get past the potentially greater complexity of checking for what I'm actually waiting for. This has multiple pitfalls though - you may be slowing down your tests too much (what if each of your waits above only needed to be 200ms, for example - now even the brief snippet above takes an extra 2.5 seconds (and that's without adjusting the 5 second wait at the end). That may not seem like much by itself but it adds up as your suite gets bigger.) Another pitfall happens when you move to a slower machine or environmental things slow down your app - what if it took 1.5 seconds before you could click the Forgotten your password? link on one machine. Your test would fail, but that may still be within acceptable performance thresholds for your app, so you now have a false failure. This is often dealt with by simply increasing the wait time, but that leads back to the first pitfall I mentioned again.
To break out of this cycle, I find it's very important to be as specific as possible when I'm waiting for things. Selenium provides a Wait class that can be used to wait until a particular condition is met. I don't know if the .Net bindings include it, but i would go into using them expecting it. In the Ruby version, we give Wait a block of code - it can look for the presence of an element or whatever else we need to check. The wait method takes a timeout value and an interval value, and then runs the block every interval seconds until either the block returns true or the timeout period has elapsed. Setting up a class like this allows you to set your timeout values high enough to handle the low end of the performance scale but not to incur the penalty of waiting a lot longer than you really need to in a given run.