Cucumber 不是瀏覽器自動化工具,但它可以與下列瀏覽器自動化工具很好地搭配使用。
Selenium WebDriver
WebDriver 的設計宗旨是提供比其他一些工具更簡單、更簡潔的程式設計介面。Selenium WebDriver 更好地支援動態網頁,其中頁面的元素可能會在不重新載入頁面的情況下發生變化。WebDriver 的目標是提供一個設計良好的物件導向 API,以改進對現代進階 Web 應用程式測試問題的支援。
Selenium-WebDriver 可用於多種程式設計語言,包括 Java、JavaScript、Ruby 和 Kotlin。
讓我們來看一個在 UI 測試中使用 Selenium WebDriver 的 Cucumber 範例,將 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)是適用於自動化網頁瀏覽器的一系列 Ruby 開放原始碼 (BSD) 程式庫。它允許您編寫更易於閱讀和維護的測試。它直接且靈活。
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
現在讓我們將 Cucumber 加入到此測試中:
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 World 時,都會移除 Rails Test::Unit
的 response.body
方法。Capybara 依賴 Nokogiri,而 Nokogiri 偏好使用 XML 而非 CSS 標籤。此行為可以在 ./features/support/env.rb
中覆寫。
關於 Capybara 的更多資訊。
Capybara 僅適用於 Ruby。Capybara 僅適用於 Ruby。Capybara 僅適用於 Ruby。提示和技巧
失敗時螢幕截圖
當情境失敗時進行螢幕截圖,可能可以幫助您找出錯誤的原因。若要在失敗時進行螢幕截圖,您可以設定一個after 勾點。
以下是一個範例,說明如何針對失敗的情境,使用 WebDriver 進行螢幕截圖,並將其嵌入 Cucumber 的報表中。
以下是一個範例,說明如何針對失敗的情境,使用 WebDriver 進行螢幕截圖,並將其嵌入 Cucumber 的報表中。
以下是一個範例,說明如何針對失敗的情境,使用 WebDriver 進行螢幕截圖,並將其嵌入 Cucumber 的報表中。
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 進行螢幕截圖,並將其嵌入 Cucumber 的報表中。
# 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
多個瀏覽器
Cucumber 可以根據執行時載入的組態屬性,在不同的瀏覽器中執行您的情境
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
然後,在您執行 Cucumber 時定義 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 中傳遞引數