문제

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("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"));
        }

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,

도움이 되었습니까?

해결책

You could use the manage functionality to set the base line time you want FindElement() to wait for before failing:

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

다른 팁

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.

**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")));
}

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.

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();

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.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top