【问题标题】:Selenium - Waiting after every line of codeSelenium - 等待每一行代码
【发布时间】:2014-05-28 21:41:59
【问题描述】:

我正在使用 Selenium (python) 来测试 Web 应用程序。但是,有时一行代码会触发错误,导致第一行没有足够的时间运行。例如:

...
driver.find_element_by_id("form_widget_date").click()
driver.find_element_by_link_text(str(self.day)).click()
...

因此,第二行(有时)找不到链接文本,因为 Selenium 显然没有时间完成第一行。当我在两行之间设置睡眠时,不会发生错误。

我的问题是:有没有办法自动为每一行代码等待更长的时间,而不是像这样解决它:

...
time.sleep(2)
driver.find_element_by_id("form_widget_date").click()
time.sleep(2)
driver.find_element_by_link_text(str(self.day)).click()
time.sleep(2) 
...

?

【问题讨论】:

    标签: python selenium webdriver


    【解决方案1】:

    你想做的事情基本上有三种选择。

    1. 使用time.sleep(...)

      对于现实世界的开发来说,这是最糟糕的选择。这太糟糕了,因为您保证每次等待金额您指定的时间。如果您发现有时您需要 5 秒才能通过测试,那么如果您等待的条件在 1 秒内准备就绪,您仍将等待 5 秒。在大量的测试套件中,这些等待将加起来,并增加运行套件所需的总时间。

    2. 使用 Selenium 的隐式等待。

      优点是你可以设置一个隐式等待而忘记它。您不必指定等待,等待之后,等待之后。但问题是隐式等待不会与显式等待混合。 this answer 很好地解释了为什么它们不混合的细节。根据我使用隐式等待的经验,仅在极其简单的情况下才有效。

    3. 使用 Selenium 的显式等待。

      如果你的应用程序是动态类型的,如果你有 Ajax,如果你动态修改 DOM,迟早你将不得不使用显式等待,那时您将不再依赖隐式等待。缺点是您的代码会更加冗长。您可以使用包装函数来缓解它。下面是一个示例,假设 driver 设置为 WebDriver 对象:

      from selenium.webdriver.common.by import By
      from selenium.webdriver.support.ui import WebDriverWait
      
      
      class MyDriver(object):
          def __init__(self, driver, default_timeout=2):
              self.driver = driver
              self.timeout = default_timeout
      
          def find_element(self, locator):
              return WebDriverWait(self.driver, self.timeout).until(
                  EC.presence_of_element_located(locator))
      
      mydriver = MyDriver(driver)
      foo = mydriver.find_element((By.CSS_SELECTOR, ".foo"))
      

    【讨论】:

      【解决方案2】:

      有两种等待 explicit waitsimplicit waits

      Dan 提供的解决方案是显式等待的示例,我认为您正在寻找的是隐式等待。

      隐式等待是告诉 WebDriver 轮询 DOM 尝试查找一个或多个元素(如果它们是)时的时间量 无法立即使用。默认设置为 0。一旦设置, 为 WebDriver 对象实例的生命周期设置了隐式等待。

      您可以像这样在开始时定义一次隐式等待时间:

      driver = webdriver.Firefox()
      driver.implicitly_wait(10) # seconds
      

      参考:Explicit and Implicit waits

      【讨论】:

        【解决方案3】:

        现实情况是,您的代码通常会以大量等待告终。你确实想避免使用睡眠思维。看一下显式等待的使用。这允许等待设定的时间段,否则执行将超时,但是当找到元素时,无论等待时间段内还剩余多少时间,它都会自动继续。

        来自selenium HQ 文档:

        from selenium import webdriver
        from selenium.webdriver.common.by import By
        from selenium.webdriver.support.ui import WebDriverWait # available since 2.4.0
        from selenium.webdriver.support import expected_conditions as EC # available since 2.26.0
        
        ff = webdriver.Firefox()
        ff.get("http://somedomain/url_that_delays_loading")
        try:
            element = WebDriverWait(ff, 10).until(EC.presence_of_element_located((By.ID, "myDynamicElement")))
        finally:
            ff.quit()
        

        【讨论】:

        • 我认为情况完全一样。对于要设置“等待”的每一行代码,我仍然必须使用它。而且,无论如何,有时我不会打开新的 url,我只是打开一个对话框或其他任何东西(例如,我上面的示例)
        • 正如我所指出的,您最终会在代码中遇到很多等待。您可以创建一个包装类,将元素传递给它会变得更整洁。想想你想如何为你的行为建模。有些步骤需要等待,有些则不需要。
        • 当我意识到有时第二行执行而有时不执行时,我担心我的代码会大两倍,因为我必须努力保持一致性:/
        • 欢迎来到 UI 自动化的精彩世界。在我的许多页面类中,我有一个简单的方法来执行操作,但它看起来像这样(java): public String CheckListingsPage() { _wait.until(ExpectedConditions.visibilityOf(listingResults));返回 bodyTag.getAttribute("id");不同的浏览器以不同的方式执行命令,因此这可以防止它在一个工作和另一个中断,而不会因睡眠而减慢整个测试的速度。
        猜你喜欢
        • 2020-12-12
        • 1970-01-01
        • 2017-02-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-06-14
        相关资源
        最近更新 更多