Selenium 2 常见问题
此文档之前位于 wiki 上 \
问:什么是 WebDriver?
答:WebDriver 是一种用于编写网站自动化测试的工具。它的目的是模仿真实用户的行为,因此会与应用程序的 HTML 进行交互。
问:那么,它像 Selenium 吗?还是 Sahi?
答:目标是相同的(允许您测试您的 Web 应用程序),但实现方式不同。WebDriver 不是在浏览器中作为 Javascript 应用程序运行(这会带来诸如“同源”问题等限制),而是控制浏览器本身。这意味着它可以利用原生平台提供的任何功能。
问:什么是 Selenium 2.0?
答:WebDriver 是 Selenium 的一部分。WebDriver 的主要贡献是其 API 和原生驱动程序。
问:如何从使用原始 Selenium API 迁移到新的 WebDriver API?
答:该过程在 Selenium 文档中描述,网址为 http://seleniumhq.org/docs/appendix_migrating_from_rc_to_webdriver.html
问:WebDriver 支持哪些浏览器?
答:现有的驱动程序是 ChromeDriver、InternetExplorerDriver、FirefoxDriver、OperaDriver 和 HtmlUnitDriver。有关每个驱动程序的更多信息,包括它们的相对优势和劣势,请单击链接到相关页面。还支持通过 AndroidDriver、OperaMobileDriver 和 IPhoneDriver 进行移动测试。
问:“以开发者为中心”是什么意思?
答:我们认为,在软件应用程序的开发团队中,最适合构建其他人都可以使用的工具的人是开发人员。虽然直接使用 WebDriver 应该很容易,但将它用作更复杂工具的基础也应该很容易。因此,WebDriver 有一个小型 API,可以通过在您最喜欢的 IDE 中点击“自动完成”按钮轻松浏览,并且无论您使用哪种浏览器实现,它的目标都是始终如一地工作。
问:如何直接执行 Javascript?
答:我们认为,在大多数情况下,需要执行 Javascript 时,所使用的工具存在缺陷:它没有发出正确的事件,没有正确地与页面交互,或者在 XmlHttpRequest 返回时没有做出反应。我们宁愿修复 WebDriver 以使其一致且正确地工作,而不是依赖测试人员找出要调用的 Javascript 方法。
我们也意识到,有时这会是一种限制。因此,对于那些支持它的浏览器,您可以通过将 WebDriver 实例转换为 JavascriptExecutor (http://selenium.googlecode.com/svn/trunk/docs/api/java/org/openqa/selenium/JavascriptExecutor.html
) 来执行 Javascript。在 Java 中,如下所示
WebDriver driver; // Assigned elsewhere
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("return document.title");
其他语言绑定将遵循类似的方法。请查看 使用Javascript 页面以获取更多信息。
问:为什么我的 Javascript 执行总是返回 null?
答:您需要从 javascript 代码片段返回一个值,因此
js.executeScript("document.title");
将返回 null,但
js.executeScript("return document.title");
将返回文档的标题。
问:我的 XPath 在一个浏览器中找到元素,但在其他浏览器中却找不到。为什么会这样?
答:简而言之,每个受支持的浏览器处理 XPath 的方式略有不同,您可能遇到了其中一个差异。详细答案在 XpathInWebDriver 页面上。
问:InternetExplorerDriver 在 Vista 上运行不佳。我该如何让它按预期工作?
答:InternetExplorerDriver 要求所有安全域都设置为相同的值(受信任或不受信任)。如果您无法修改安全域,则可以像这样覆盖检查
DesiredCapabilities capabilities = DesiredCapabilities.internetExplorer();
capabilities.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true);
WebDriver driver = new InternetExplorerDriver(capabilities);
正如常量的名称所表明的那样,这可能会在您的测试中引入不稳定性。如果所有站点都位于同一保护域中,那么您应该没有问题。
问:除了 Java 之外,还支持其他语言吗?
答:开发团队直接支持 Python、Ruby、C# 和 Java。还有 PHP 和 Perl 的 WebDriver 实现。还计划支持纯 JS API。
问:如何处理弹出窗口?
答:WebDriver 提供了处理多个窗口的功能。这是通过使用“WebDriver.switchTo().window()”方法切换到具有已知名称的窗口来完成的。如果名称未知,可以使用“WebDriver.getWindowHandles()”获取已知窗口的列表。您可以将句柄传递给“switchTo().window()”。
问:WebDriver 支持 Javascript 警告和提示吗?
答:是的,可以使用 Alerts API (http://selenium.googlecode.com/svn/trunk/docs/api/java/org/openqa/selenium/Alert.html
)
// Get a handle to the open alert, prompt or confirmation
Alert alert = driver.switchTo().alert();
// Get the text of the alert or prompt
alert.getText();
// And acknowledge the alert (equivalent to clicking "OK")
alert.accept();
问:WebDriver 支持文件上传吗?
答:是的。
您不能直接与原生的操作系统文件浏览器对话框交互,但我们做了一些魔法,所以如果您在文件上传元素上调用 WebElement#sendKeys("/path/to/file"),它会执行正确的操作。请确保您不要对文件上传元素使用 WebElement#click(),否则浏览器可能会挂起。
实用提示:您不能与隐藏元素交互,除非将其取消隐藏。如果您的元素被隐藏,它很可能可以使用类似下面的代码取消隐藏:
((JavascriptExecutor)driver).executeScript("arguments[0].style.visibility = 'visible'; arguments[0].style.height = '1px'; arguments[0].style.width = '1px'; arguments[0].style.opacity = 1", fileUploadElement);
问:在调用 “sendKeys” 后,“onchange” 事件不会触发
答:WebDriver 将焦点保留在您调用 “sendKeys” 的元素上。“onchange” 事件只有在焦点离开该元素时才会触发。因此,您需要移动焦点,也许可以使用“点击”其他元素。
问:我可以运行 WebDriver 子类的多个实例吗?
答:HtmlUnitDriver、ChromeDriver 和 FirefoxDriver 的每个实例都与其他每个实例完全独立(对于 Firefox 和 Chrome,每个实例都有自己使用的匿名配置文件)。由于 Windows 的工作方式,一次应该只有一个 InternetExplorerDriver 实例。如果您需要一次运行多个 InternetExplorerDriver 实例,请考虑使用 Remote!WebDriver 和虚拟机。
问:我需要使用代理。我该如何配置?
答:代理配置是通过 org.openqa.selenium.Proxy
类完成的,如下所示:
Proxy proxy = new Proxy();
proxy.setProxyAutoconfigUrl("http://youdomain/config");
// We use firefox as an example here.
DesiredCapabilities capabilities = DesiredCapabilities.firefox();
capabilities.setCapability(CapabilityType.PROXY, proxy);
// You could use any webdriver implementation here
WebDriver driver = new FirefoxDriver(capabilities);
问:如何处理 HtmlUnitDriver 的身份验证?
答:在创建 HtmlUnitDriver 实例时,覆盖 “modifyWebClient” 方法,例如:
WebDriver driver = new HtmlUnitDriver() {
protected WebClient modifyWebClient(WebClient client) {
// This class ships with HtmlUnit itself
DefaultCredentialsProvider creds = new DefaultCredentialsProvider();
// Set some example credentials
creds.addCredentials("username", "password");
// And now add the provider to the webClient instance
client.setCredentialsProvider(creds);
return client;
}
};
问:WebDriver 是线程安全的吗?
答:WebDriver 不是线程安全的。话虽如此,如果您可以序列化对底层驱动程序实例的访问,则可以在多个线程中共享引用。这是不可取的。另一方面,您可以为每个线程实例化一个 WebDriver 实例。
问:如何输入到 contentEditable 的 iframe 中?
答:假设 iframe 被命名为 “foo”
driver.switchTo().frame("foo");
WebElement editable = driver.switchTo().activeElement();
editable.sendKeys("Your text here");
有时这不起作用,这是因为 iframe 没有内容。在 Firefox 上,您可以在 “sendKeys” 之前执行以下操作:
((JavascriptExecutor) driver).executeScript("document.body.innerHTML = '<br>'");
这是必需的,因为 iframe 默认情况下没有内容:没有什么可以发送键盘输入。此方法调用会插入一个空标签,从而将一切都设置好。
请记住,一旦完成,请切换出框架(因为所有进一步的交互都将与此特定框架进行)
driver.switchTo().defaultContent();
问:由于 java.net.SocketException,WebDriver 无法在 Linux 上启动 Firefox
答:如果在 Linux 上运行 WebDriver 时,Firefox 无法启动并且错误看起来像:
Caused by: java.net.SocketException: Invalid argument
at java.net.PlainSocketImpl.socketBind(Native Method)
at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:365)
at java.net.Socket.bind(Socket.java:571)
at org.openqa.selenium.firefox.internal.SocketLock.isLockFree(SocketLock.java:99)
at org.openqa.selenium.firefox.internal.SocketLock.lock(SocketLock.java:63)
这可能是由于机器上的 IPv6 设置引起的。执行
sudo sysctl net.ipv6.bindv6only=0
以使套接字通过相同的调用绑定到主机的 IPv6 和 IPv4 地址。更永久的解决方案是通过编辑 /etc/sysctl.d/bindv6only.conf 来禁用此行为
问:WebDriver 无法找到元素/在页面加载时不会阻塞
答:此问题可能以各种方式表现出来
- 使用 WebDriver.findElement(…) 抛出 ElementNotFoundException,但该元素显然存在 - 检查 DOM(使用 Firebug 等)清楚地显示了它。
- 调用 Driver.get 在 HTML 加载后返回 - 但 onload 事件触发的 Javascript 代码尚未完成,因此页面不完整,并且某些元素无法找到。
- 单击元素/链接会触发创建新元素的操作。但是,单击后调用 findElement(s) 不会找到它。单击不应该是阻塞的吗?
- 我如何知道页面何时加载完成?
解释:WebDriver 通常具有阻塞 API。但是,在某些情况下,get 调用可能会在页面加载完成之前返回。一个经典的例子是 Javascript 在页面加载后开始运行(由 onload 触发)。浏览器(例如 Firefox)会在基本 HTML 内容加载完成后通知 WebDriver,此时 WebDriver 返回。很难(如果不是不可能)知道 Javascript 何时完成执行,因为 JS 代码可能会安排将来调用的函数,依赖服务器响应等等。单击也是如此 - 当平台支持本机事件(Windows、Linux)时,单击是通过在操作系统级别发送带有元素坐标的鼠标单击事件来完成的 - WebDriver 无法跟踪此单击创建的确切操作顺序。因此,阻塞 API 是不完美的 - WebDriver 无法在测试继续之前等待所有条件得到满足,因为它不知道这些条件。通常,重要的是下一个交互中涉及的元素是否存在并且已准备好。
解决方案:使用 Wait 类来等待特定元素出现。此类只是重复调用 findElement,每次都丢弃 NoSuchElementException,直到找到该元素(或超时过期)。由于这是许多用户默认情况下期望的行为,因此已经实现了一种隐式等待元素出现的机制。可以通过 WebDriver.manage().timeouts() 调用访问此机制。(这之前在问题 26 上跟踪过)。
问:如何在页面上触发任意事件?
答:WebDriver 旨在模拟用户交互 - 因此 API 反映了用户可以与各种元素交互的方式。
不能使用 API 直接触发特定事件,但是可以使用 Javascript 执行功能来调用元素上的方法。
问:为什么不能与隐藏的元素交互?
答:由于用户无法读取隐藏元素中的文本,WebDriver 也不会允许访问它。
但是,可以使用 Javascript 执行功能直接从元素调用 getText
WebElement element = ...;
((JavascriptExecutor) driver).executeScript("return arguments[0].getText();", element);
问:如何启动已安装扩展程序的 Firefox?
答
FirefoxProfile profile = new FirefoxProfile()
profile.addExtension(....);
WebDriver driver = new FirefoxDriver(profile);
问:我希望 WebDriver 可以做到……。
答:如果您希望 WebDriver 执行某些操作,或者您发现了错误,请在 WebDriver 项目页面上添加一个问题。
问:Selenium 服务器有时需要很长时间才能启动新会话?
答:如果您在 Linux 上运行,则需要增加可用于安全随机数生成熵的量。大多数 Linux 发行版可以安装一个名为“randomsound”的软件包来执行此操作。
在 Windows (XP) 上,您可能会遇到 http://bugs.sun.com/view_bug.do?bug_id=6705872,这通常意味着清除临时目录中的大量文件。临时目录。
问:Selenium WebDriver API 中与 TextPresent 等效的是什么?
答
driver.findElement(By.tagName("body")).getText()
将获取页面的文本。要验证文本是否存在/断言文本是否存在,您可以从该文本使用您最喜欢的测试框架来断言文本。要等待文本是否存在,您可能需要研究 WebDriverWait 类。
问:套接字锁定似乎设计得很糟糕。我可以做得更好
答:用于保护 Firefox 启动的套接字锁是按照以下设计约束构建的:
- 它在所有语言绑定之间共享;ruby、java 和任何其他绑定可以在同一台机器上同时共存。
- 启动 Firefox 的某些关键部分必须在该机器上独占锁定。
- 套接字锁本身不是主要瓶颈,启动 Firefox 才是。
SocketLock 是 Lock 接口的实现。这允许为您的自定义实现提供可插拔的策略。要切换到不同的实现,请子类化 FirefoxDriver 并覆盖 “obtainLock” 方法。
问:为什么我在 python 中使用 send_keys 时会收到 UnicodeEncodeError
答:您的系统可能未设置区域设置。请为您的 locale
设置 LANG=en_US.UTF-8 和 LC_CTYPE=“en_US.UTF-8”,例如。