黄瓜不是浏览器自动化工具,但它与以下浏览器自动化工具配合得很好。
Selenium WebDriver
WebDriver 旨在提供比其他一些工具更简单、更简洁的编程接口。Selenium WebDriver 更好地支持动态网页,其中页面的元素可能会发生变化,而页面本身不会重新加载。WebDriver 的目标是提供一个精心设计的面向对象 API,以改进对现代高级 Web 应用程序测试问题的支持。
Selenium-WebDriver 可用于多种编程语言,包括 Java、JavaScript、Ruby 和 Kotlin。
让我们通过将 Selenium WebDriver 入门 转换为 UI 测试示例,来看看使用 Selenium WebDriver 的黄瓜示例。
我们可以将示例表达为以下场景
Scenario: Finding some cheese
Given I am on the Google search page
When I search for "Cheese!"
Then the page title should start with "cheese"
package com.example;
import io.cucumber.java.After;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
public class ExampleSteps {
private final WebDriver driver = new FirefoxDriver();
@Given("I am on the Google search page")
public void I_visit_google() {
driver.get("https://www.google.com");
}
@When("I search for {string}")
public void search_for(String query) {
WebElement element = driver.findElement(By.name("q"));
// Enter something to search for
element.sendKeys(query);
// Now submit the form. WebDriver will find the form for us from the element
element.submit();
}
@Then("the page title should start with {string}")
public void checkTitle(String titleStartsWith) {
// Google's search is rendered dynamically with JavaScript
// Wait for the page to load timeout after ten seconds
new WebDriverWait(driver,10L).until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
return d.getTitle().toLowerCase().startsWith(titleStartsWith);
}
});
}
@After()
public void closeBrowser() {
driver.quit();
}
}
package com.example
import io.cucumber.java8.Scenario
import io.cucumber.java8.En
import org.openqa.selenium.By
import org.openqa.selenium.WebDriver
import org.openqa.selenium.WebElement
import org.openqa.selenium.support.ui.WebDriverWait
class ExampleSteps: En {
lateinit var driver: WebDriver
init {
Given("I am on the Google search page") {
driver.get("https:\\www.google.com")
}
When("I search for {string}") { query: String ->
val element: WebElement = driver.findElement(By.name("q"))
// Enter something to search for
element.sendKeys(query)
// Now submit the form. WebDriver will find the form for us from the element
element.submit()
}
Then("the page title should start with {string}") { titleStartsWith: String ->
// Google's search is rendered dynamically with JavaScript
// Wait for the page to load timeout after ten seconds
WebDriverWait(driver, 10L).until { d ->
d.title.toLowerCase().startsWith(titleStartsWith)
}
}
After { scenario: Scenario ->
driver.quit()
}
}
}
const { Given, When, Then, AfterAll } = require('cucumber');
const { Builder, By, Capabilities, Key } = require('selenium-webdriver');
const { expect } = require('chai');
require("chromedriver");
// driver setup
const capabilities = Capabilities.chrome();
capabilities.set('chromeOptions', { "w3c": false });
const driver = new Builder().withCapabilities(capabilities).build();
Given('I am on the Google search page', async function () {
await driver.get('http://www.google.com');
});
When('I search for {string}', async function (searchTerm) {
const element = await driver.findElement(By.name('q'));
element.sendKeys(searchTerm, Key.RETURN);
element.submit();
});
Then('the page title should start with {string}', {timeout: 60 * 1000}, async function (searchTerm) {
const title = await driver.getTitle();
const isTitleStartWithCheese = title.toLowerCase().lastIndexOf(`${searchTerm}`, 0) === 0;
expect(isTitleStartWithCheese).to.equal(true);
});
AfterAll(async function(){
await driver.quit();
});
require 'rubygems'
require 'selenium-webdriver'
Given(/^I am on the Google search page$/) do
driver = Selenium::WebDriver.for :firefox
driver.get "http://google.com"
end
When(/^I search for "([^"]*)"$/) do
element = driver.find_element(name: "q")
element.send_keys "Cheese!"
element.submit
end
Then(/^the page title should start with "([^"]*)"$/) do
wait = Selenium::WebDriver::Wait.new(timeout: 10)
wait.until { driver.title.downcase.start_with? "cheese!" }
puts "Page title is #{driver.title}"
browser.close
end
有关 Selenium Webdriver 的更多信息。
适用于 JVM 的浏览器自动化工具
Serenity BDD
Serenity BDD 是一个开源报告库,它可以帮助您编写结构更合理、更易于维护的自动化验收标准。Serenity 还生成丰富的、有意义的测试报告(或“活文档”),这些报告不仅报告测试结果,还报告已测试的功能。
有关使用 Cucumber-JVM 与 Serenity 的详细教程,请参阅 此处,有关 Serenity 的更多信息,请访问其 官方网站。
Serenity BDD 是一个开源报告库,它可以帮助您编写结构更合理、更易于维护的自动化验收标准。Serenity 还生成丰富的、有意义的测试报告(或“活文档”),这些报告不仅报告测试结果,还报告已测试的功能。
有关使用 Cucumber-JVM 与 Serenity 的详细教程,请参阅 此处,有关 Serenity 的更多信息,请访问其 官方网站。
Serenity 仅适用于 JVM 语言。Serenity 仅适用于 JVM 语言。适用于 Ruby 的浏览器自动化工具
Watir
Watir(发音为 water)是一个开源(BSD)的 Ruby 库系列,用于自动化 Web 浏览器。它允许您编写更容易阅读和维护的测试。它简单直观且灵活。
Watir 以人们使用的方式驱动浏览器。它可以点击链接、填写表单、按下按钮。Watir 还可以检查结果,例如页面上是否出现了预期文本。
Watir 是一个 Ruby 库系列,但无论您的应用程序是用哪种技术开发的,它都支持您的应用程序。虽然 Watir 仅在 Windows 上支持 Internet Explorer;Watir-WebDriver 解决单浏览器测试问题,并支持 Chrome、Firefox、Internet Explorer、Opera,以及以无头模式运行(HTMLUnit)。
现在让我们进入一个使用 Watir 的示例 UI 测试程序:
require "rubygems" require "rspec" require "watir" describe "google.com" do let(:browser) { @browser ||= Watir::Browser.new :firefox } before { browser.goto "http://google.com" } browser.text_field(name: "q").set "watir" browser.button.click browser.div(id: "resultStats").wait_until browser.title.should == "watir - Google Search" after { browser.close } end
现在让我们将黄瓜合并到此测试中:
Feature: Search In order to use Google users must be able to search for content Scenario: Search for a term Given I have entered "watir" into the query When I click "search" Then I should see some results
require "watir" require "rspec/expectations" Given(/^I have entered "([^"]*)" into the query$/) do |term| @browser ||= Watir::Browser.new :firefox @browser.goto "google.com" @browser.text_field(name: "q").set term end When(/^I click "([^"]*)"$/) do @browser.button.click end Then(/^I should see some results$/) do @browser.div(id: "resultStats").wait_until_present @browser.close end
有关 Watir 的更多信息。
Watir 仅适用于 Ruby。Watir 仅适用于 Ruby。Watir 仅适用于 Ruby。Capybara
Cucumber-Rails 预先配置了对使用 Capybara(script/generate cucumber --capybara
)进行视图集成测试的支持。
除非另有指示,否则 Cucumber-Rails 安装生成器将为 Capybara 设置必要的支持文件。
虽然 Capybara 是在 cucumber-rails 中用于 HTML 视图的首选测试方法,但它与 Rails 自身内置的 MiniTest/Test::Unit
配合得不好。特别是,每当 Capybara 被要求进入 Cucumber 世界时,Rails Test::Unit
的 response.body
方法就会被删除。Capybara 依赖于 Nokogiri,而 Nokogiri 更喜欢使用 XML 而不是 CSS 标签。此行为可以在 ./features/support/env.rb
中覆盖。
有关 Capybara 的更多信息。
Capybara 仅适用于 Ruby。Capybara 仅适用于 Ruby。Capybara 仅适用于 Ruby。提示和技巧
失败时截屏
在场景失败时截取屏幕截图,可能有助于您找出问题所在。要在失败时截取屏幕截图,您可以配置 after 钩子。
以下是使用 WebDriver 为失败的场景截取屏幕截图并将其嵌入黄瓜报告中的示例。
以下是使用 WebDriver 为失败的场景截取屏幕截图并将其嵌入黄瓜报告中的示例。
以下是使用 WebDriver 为失败的场景截取屏幕截图并将其嵌入黄瓜报告中的示例。
if (scenario.isFailed()) {
byte[] screenshot = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.BYTES);
scenario.attach(screenshot, "image/png", "name");
}
if (scenario.isFailed()) {
val screenshot = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.BYTES)
scenario.attach(screenshot, "image/png", "name")
}
After(function (scenario) {
if (scenario.result.status === Status.FAILED) {
var world = this;
return webDriver.takeScreenshot().then(function(screenShot, error) {
if (!error) {
world.attach(screenShot, "image/png");
}
});
}
});
以下是使用 Capybara 为失败的场景截取屏幕截图并将其嵌入黄瓜报告中的示例。
# Available scenario methods: #failed?, #passed?, and #exception
if scenario.failed?
path = "html-report/#{scenario.__id__}.html"
page.driver.browser.save_screenshot(path)
attach(path, "image/png")
end
多个浏览器
黄瓜可以在运行时加载的配置属性的基础上,使用不同的浏览器运行您的场景
Capybara.register_driver :selenium do |app|
browser = (ENV['browser'] || 'firefox').to_sym
Capybara::Selenium::Driver.new(app, browser: browser)
end
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class WebDriverFactory {
public static WebDriver createWebDriver() {
String webdriver = System.getProperty("browser", "firefox");
switch(webdriver) {
case "firefox":
return new FirefoxDriver();
case "chrome":
return new ChromeDriver();
default:
throw new RuntimeException("Unsupported webdriver: " + webdriver);
}
}
}
// TODO: Convert Java example to Kotlin
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class WebDriverFactory {
public static WebDriver createWebDriver() {
String webdriver = System.getProperty("browser", "firefox");
switch(webdriver) {
case "firefox":
return new FirefoxDriver();
case "chrome":
return new ChromeDriver();
default:
throw new RuntimeException("Unsupported webdriver: " + webdriver);
}
}
}
// TODO
然后,在运行黄瓜时定义 browser
属性:
browser=chrome cucumber
mvn test -Dbrowser=chrome
如果您使用的是 Serenity,请传递 driver
系统属性(无需额外的代码):
mvn test -Ddriver=chrome
mvn test -Dbrowser=chrome
如果您使用的是 Serenity,请传递 driver
系统属性(无需额外的代码):
mvn test -Ddriver=chrome
// TODO: 如何在 JavaScript 中传递参数