最新翻译(2020/12/1)已更新在个人博客:https://www.nothinghere.cn/gauge/overview/
备注:语言执行器的一些行为是可以配置的,参阅配置语言执行器获取更多信息。
步骤实现
步骤具有执行spec时执行的具体语言实现。
简单步骤
步骤
* Say “hello” to “gauge”
实现
C#
// The Method can be written in **any C# class** as long as it is part of the project.
public class StepImplementation {
[Step("Say <greeting> to <product name>")]
public void HelloWorld(string greeting, string name) {
// Step implementation
}
}
Java
// This Method can be written in any java class as long as it is in classpath.
public class StepImplementation {
@Step("Say <greeting> to <product name>")
public void helloWorld(String greeting, String name) {
// Step implementation
}
}
Ruby
step 'Say <greeting> to <product name>' do |greeting, name|
# Code for the step
end
使用表格的步骤
步骤
* Create following “hobbit” characters
|id |name |
|—|-------|
|123|frodo |
|456|bilbo |
|789|samwise|
实现
C#
// Here Table is a custom data structure defined by gauge.
// This is available by adding a reference to the Gauge.CSharp.Lib.
// Refer : http://nuget.org/packages/Gauge.CSharp.Lib/
public class Users {
[Step("Create following <role> users <table>")]
public void HelloWorld(string role, Table table) {
// Step implementation
}
}
Java
// Table is a custom data structure defined by gauge.
public class Users {
@Step("Create following <race> characters <table>")
public void createCharacters(String type, Table table) {
// Step implementation
}
}
Ruby
# Here table is a custom data structure defined by gauge-ruby.
step 'Create following <race> characters <table>' do |role, table|
puts table.rows
puts table.columns
end
执行hooks
在测试套件执行期间,可以使用测试执行钩子作为不同的级别运行任意测试代码。
实现
C#
public class ExecutionHooks
{
[BeforeSuite]
public void BeforeSuite() {
// Code for before suite
}
[AfterSuite]
public void AfterSuite() {
// Code for after suite
}
[BeforeSpec]
public void BeforeSpec() {
// Code for before spec
}
[AfterSpec]
public void AfterSpec() {
// Code for after spec
}
[BeforeScenario]
public void BeforeScenario() {
// Code for before scenario
}
[AfterScenario]
public void AfterScenario() {
// Code for after scenario
}
[BeforeStep]
public void BeforeStep() {
// Code for before step
}
[AfterStep]
public void AfterStep() {
// Code for after step
}
}
Java
public class ExecutionHooks {
@BeforeSuite public void BeforeSuite() {
// Code for before suite
}
@AfterSuite
public void AfterSuite() {
// Code for after suite
}
@BeforeSpec
public void BeforeSpec() {
// Code for before spec
}
@AfterSpec
public void AfterSpec() {
// Code for after spec
}
@BeforeScenario
public void BeforeScenario() {
// Code for before scenario
}
@AfterScenario
public void AfterScenario() {
// Code for after scenario
}
@BeforeStep
public void BeforeStep() {
// Code for before step
}
@AfterStep
public void AfterStep() {
// Code for after step
}
}
Ruby
before_suite do
# Code for before suite
end
after_suite do
# Code for after suite
end
before_spec do
# Code for before spec
end
after_spec do
# Code for after spec
end
before_scenario do
# Code for before scenario
end
after_scenario do
# Code for after scenario
end
before_step do
# Code for before step
end
after_step do
# Code for after step
end
默认情况下,gauge清除每个场景后的状态,以便为下一个场景执行创建新对象。您可以配置更改gauge清除缓存的级别。
数据存储
数据(对象)可以在运行时通过Gauge公开的DataStores在不同类中定义的步骤共享。
根据清除时的生命周期,有三种不同类型的DataStores。
ScenarioStore
该数据存储在场景执行的生命周期中保留添加的值,在每个场景执行后,值被清除。
C#
using Gauge.CSharp.Lib;
// Adding value
var scenarioStore = DataStoreFactory.ScenarioDataStore;
scenarioStore.Add("element-id", "455678");
// Fetching Value
var elementId = (string) scenarioStore.Get("element-id");
// avoid type cast by using generic Get
var anotherElementId = scenarioStore.Get("element-id");
Java
import com.thoughtworks.gauge.datastore.*;
// Adding value
DataStore scenarioStore = DataStoreFactory.getScenarioDataStore();
scenarioStore.put("element-id", "455678");
// Fetching Value
String elementId = (String) scenarioStore.get("element-id");
Ruby
// Adding value
scenario_store = DataStoreFactory.scenario_datastore;
scenario_store.put("element-id", "455678");
// Fetching Value
element_id = scenario_store.get("element-id");
SpecStore
该数据存储在spec执行的生命周期中保留添加的值,在每个spec执行后,值被清除。
C#
using Gauge.CSharp.Lib;
// Adding value
var specStore = DataStoreFactory.SpecDataStore;
specStore.Add("element-id", "455678");
// Fetching Value
var elementId = (string) specStore.Get("element-id");
// avoid type cast by using generic Get
var anotherElementId = specStore.Get("element-id");
Java
// Import Package
import com.thoughtworks.gauge.datastore.*;
// Adding value
DataStore specStore = DataStoreFactory.getSpecDataStore();
specStore.put("key", "455678");
// Fetching value
DataStore specStore = DataStoreFactory.getSpecDataStore();
String elementId = (String) specStore.get("key");
Ruby
// Adding value
spec_store = DataStoreFactory.spec_datastore;
spec_store.put("element-id", "455678");
// Fetching Value
element_id = spec_store.get("element-id");
SuiteStore
该数据存储在整个测试套件执行的生命周期中保留添加的值,在整个测试套件执行后,值被清除。
警告:并行执行spec时不建议使用SuiteStore,在并行执行流之间不保留这些值。
Java
// Import Package
import com.thoughtworks.gauge.datastore.*;
// Adding value
DataStore suiteStore = DataStoreFactory.getSuiteDataStore();
suiteStore.put("element-id", "455678");
// Fetching value
DataStore suiteStore = DataStoreFactory.getSuiteDataStore();
String elementId = (String) suiteStore.get("element-id");
Ruby
// Adding value
suite_store = DataStoreFactory.suite_datastore;
suite_store.put("element-id", "455678");
// Fetching Value
suite_store = DataStoreFactory.suite_datastore;
element_id = suite_store.get("element-id");
采用自定义截图
- 如果此功能被打开,默认情况下会在失败的时候截图;
- 因为您需要截取屏幕一部分,而需要捕获自定义截图(例如使用webdriver),这可以通过实现
ICustomScreenshotGrabber
(C#里是IScreenGrabber
)接口来完成。
备注:如果在classpath中多个自定义截图功能被实现,gauge会随机选择其一来截图。因为gauge会选择它找到的第一个实现的截图功能,这又取决于库的扫描顺序。
Java
// Using Webdriver public class
CustomScreenGrabber implements ICustomScreenshotGrabber {
// Return a screenshot byte array
public byte[] takeScreenshot() {
WebDriver driver = DriverFactory.getDriver();
return ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
}
}
C#
//Using Webdriver public
class CustomScreenGrabber : IScreenGrabber {
// Return a screenshot byte array
public byte[] TakeScreenshot() {
var driver = DriverFactory.getDriver();
return ((ITakesScreenshot) driver).GetScreenshot().AsByteArray;
}
}
Ruby
# Using Webdriver
Gauge.configure do |config|
# Return a screenshot byte array
config.screengrabber = -> {
driver.save_screenshot('/tmp/screenshot.png')
return File.binread("/tmp/screenshot.png")
}
end
报告中的自定义信息
自定义消息/数据可以通过使用下面步骤实现中的API或者Hooks被添加到执行报告中。
这些信息会展示在执行报告中步骤底下。
C#
GaugeMessages.WriteMessage("Custom message for report");
var id = "4567";
GaugeMessages.WriteMessage("User id is {0}", id);
Java
Gauge.writeMessage("Custom message for report");
String id = "4567";
Gauge.writeMessage("User id is %s", id);
Ruby
Gauge.write_message("Custom message for report")
id = "4567"
Gauge.write_message("User id is" + id)
枚举作为步骤参数
枚举数据类型的常量值可以用作步骤的参数,但是在步骤实现中,参数的类型应与枚举名称本身匹配。
步骤:
* Navigate towards "SOUTH"
实现:
Java
public enum Direction { NORTH, SOUTH, EAST, WEST; }
@Step("Navigate towards ")
public void navigate(Direction direction) {
// code here
}
失败后继续执行
Gauge默认在步骤中的第一个失败时中断执行。所以如果场景中的第一个步骤失败了,随后的所有步骤都将跳过执行。
虽然这适用于大多数用例,但是有时您需要执行场景中的所有步骤,而不管前面的步骤是否失败。
为了解决这个要求,Gauge为语言执行器提供了一种方法,可以将步骤标记为可恢复,具体取决于步骤实现是否明确要求它。每个语言执行器使用不同的语法,具体取决于语言习语,允许标记步骤实现为失败继续执行。
Java
// The ``@ContinueOnFailure`` annotation tells Gauge to continue executing other
// steps even if the current step fails.
public class StepImplementation {
@ContinueOnFailure
@Step("Say <greeting> to <product name>")
public void helloWorld(String greeting, String name) {
// If there is an error here, Gauge will still execute next steps
}
}
C#
// The ``[ContinueOnFailure]`` attribute tells Gauge to continue executing others
// steps even if the current step fails.
public class StepImplementation {
[ContinueOnFailure]
[Step("Say <greeting> to <product name>")]
public void HelloWorld(string greeting, string name) {
// If there is an error here, Gauge will still execute next steps
}
}
Ruby
# The ``:continue_on_failure => true`` keyword argument
# tells Gauge to continue executing other steps even
# if the current step fails.
step 'Say <greeting> to <name>', :continue_on_failure => true do |greeting, name|
# If there is an error here, Gauge will still execute next steps
end
失败继续执行可以使用可选参数来指定错误类的列表,在错误类列表中,它将在失败时继续执行进一步的步骤。目前仅支持Java。
Java
@ContinueOnFailure({AssertionError.class, CustomError.class})
@Step("hello")
public void sayHello() {
// code here
}
@ContinueOnFailure(AssertionError.class)
@Step("hello")
public void sayHello() {
// code here
}
@ContinueOnFailure
@Step("hello")
public void sayHello() {
// code here
}
如果没有参数传递给@ContinueOnFailure
,默认情况下,任何类型的错误都将会继续执行下一个步骤。
这可以用于控制执行应该继续的错误类型,而不是继续每种类型的错误。例如,在RuntimeException上,最好不要继续。而如果它是断言错误,继续执行可能会很好。
备注:
- 在执行后,即在执行步骤方法之后,失败继续进行。如果执行步骤失败,例如参数计数/类型不匹配,gauge将不符合ContinueOnFailure标志。
- Hooks不适用与失败继续执行,Hooks总在第一个错误时失败。
- 默认情况下,步骤执行仍不可恢复,Gauge在执行失败时不执行后续步骤。要使失败的步骤继续执行,需要在测试代码中明确标注。
- 没有办法全局标记测试运行,已处理所有步骤失败继续执行。每个步骤的实现必须明确标记。
- 如果一个实现使用步骤别名,标记该实现失败继续执行也将使所有别名失败继续执行。因此,如果一个别名应该在失败时中断,另一个步骤别名应该失败继续执行,则需要将其提取到两个不同的步骤。
章节指引
一、安装
二、快速开始
三、深入开始
四、Gauge使用
五、语法
六、插件
七、语言特点
八、报告
九、配置
十、故障处理
十一、项目实例
十二、怎么做?