Cucumber - 快速指南


Cucumber - 概述

为了更好地利用软件测试,组织现在正在向前迈出一步。他们在开发过程中实施重要的验收测试场景。这种方法通常称为Behave驱动开发(BDD)。

Behave驱动开发使我们有机会从开发人员和客户的角度创建测试脚本。因此,一开始,开发人员、项目经理、质量保证人员、用户验收测试人员和产品所有者(股东)齐聚一堂,集思广益,讨论应该通过哪些测试场景才能使该软件/应用程序成功。通过这种方式,他们提出了一组测试场景。所有这些测试脚本都是简单的英语,因此它也可以用于文档的目的。

例子

如果我们正在开发用户身份验证功能,那么以下可能是几个关键的测试场景,需要通过这些测试场景才能称为成功。

  • 用户应该能够使用正确的用户名和密码登录。

  • 用户应该无法使用错误的用户名和正确的密码登录。

  • 用户应该无法使用正确的用户名和错误的密码登录。

怎么运行的

当代码准备好时,测试脚本也准备好了。代码必须通过 BDD 中定义的测试脚本。如果没有发生,则需要重构代码。仅在成功执行定义的测试脚本后代码才会冻结。

BDD

这是一个非常简单的概念,但我们需要什么才能实现这个概念。答案是Behave驱动开发(BDD)框架。Cucumber 就是这样一种开源工具,它支持Behave驱动开发。更准确地说,Cucumber 可以定义为一个由纯英文文本驱动的测试框架。它集文档、自动化测试和开发辅助于一体。

那么Cucumber有什么作用呢?可以通过以下步骤进行描述 -

Cucumber 读取功能文件(稍后介绍)中以纯英文文本(语言 Gherkin - 将在本教程后面介绍)编写的代码。

它找到步骤定义中每个步骤的精确匹配(代码文件 - 本教程稍后提供详细信息)。

要执行的代码片段可以是不同的软件框架,例如Selenium、Ruby on Rails等。并非每个 BDD 框架工具都支持所有工具。

这成为 Cucumber 相对于其他框架(如JBehave、JDave、Easyb等)受欢迎的原因。

Cucumber 支持十几种不同的软件平台,例如 -

  • Ruby on Rails
  • Selenium
  • 微微容器
  • Spring框架
  • Watir

Cucumber 相对于其他工具的优势

  • Cucumber 支持不同的语言,例如 Java.net 和 Ruby。

  • 它充当业务和技术语言之间的桥梁。我们可以通过用纯英文文本创建测试用例来实现这一点。

  • 它允许在不了解任何代码的情况下编写测试脚本,也允许非程序员的参与。

  • 与其他工具不同,它的目的是提供端到端测试框架。

  • 由于简单的测试脚本架构,Cucumber 提供了代码可重用性。

Cucumber - 环境

在本章中,我们将看到在 Windows 机器上使用 Selenium WebDriver 和 Java 来设置 Cucumber 的环境。

环境设置的先决条件

以下是设置所需的先决条件 -

爪哇

为什么我们需要- Java 是一种强大的编程语言。Cucumber支持Java平台执行。

如何安装-

步骤 1 - 从以下链接下载 jdk 和 jre http://www.oracle.com/technetwork/java/javase/downloads/index.html

步骤 2 - 接受许可协议。

步骤 3 - 安装 JDK 和 JRE。

步骤 4 - 设置环境变量,如以下屏幕截图所示。

系统属性

编辑系统变量

为什么我们需要- Eclipse 是一个集成开发环境 (IDE)。它包含一个基础工作区和一个用于自定义环境的可扩展插件系统。

如何安装-

步骤 1 - 确保您的计算机上安装了 JAVA。

步骤 2 - 从https://eclipse.org/downloads/下载 Eclipse

步骤 3 - 解压并安装 Eclipse。

梅文

为什么我们需要- Maven 是一个主要用于 Java 项目的构建自动化工具。它提供了一个通用平台来执行生成源代码、编译代码、将代码打包到 jar 等活动。以后如果任何软件版本发生更改,Maven 提供了一种简单的方法来相应地修改测试项目。

如何安装-

步骤 1 - 从以下链接下载 Maven - https://maven.apache.org/download.cgi

步骤 2 - 解压缩文件并记住位置。

步骤 3 - 创建环境变量 MAVEN_HOME,如以下屏幕截图所示。

系统变量

步骤 4 - 编辑 Path 变量并包含 Maven,如以下屏幕截图所示。

编辑路径变量

步骤 5 - 从 Eclipse 下载 MAVEN 插件。

步骤 6 - 打开 Eclipse。

步骤 7 - 转到帮助 → Eclipse Marketplace → 搜索 Maven → Maven Integration for Eclipse → 安装。

使用 Maven 配置 Cucumber

步骤 1 - 创建一个 Maven 项目。

  • 转到文件 → 新建 → 其他 → Maven → Maven 项目 → 下一步。

  • 提供组 ID(组 ID 将在所有项目中唯一标识您的项目)。

  • 提供artifact Id(artifact Id是不带版本的jar的名称。您可以选择任何名称,小写)。单击“完成”。

新的 Maven 项目

步骤 2 - 打开 pom.xml。

  • 转到 Eclipse 左侧的包资源管理器。

  • 展开项目CucumberTest

  • 找到pom.xml文件。

  • 右键单击并选择选项,使用“文本编辑器”打开。

步骤 3 - 添加 selenium 的依赖关系:这将指示 Maven 要将哪些 Selenium jar 文件从中央存储库下载到本地存储库。

  • 在编辑模式下打开pom.xml ,在项目标签内创建依赖项标签(<dependency></dependency>)。

  • 在依赖项标记内,创建依赖项标记 (<dependency></dependency>)。

  • 在依赖项标记中提供以下信息。

<dependency> 
   <groupId>org.seleniumhq.selenium</groupId> 
   <artifactId>selenium-java</artifactId> 
   <version>2.47.1</version> 
</dependency>

步骤 4 - 添加 Cucumber-Java 的依赖项:这将指示 Maven,哪些 Cucumber 文件将从中央存储库下载到本地存储库。

  • 再创建一个依赖标记。

  • 在依赖标签中提供以下信息

<dependency> 
   <groupId>info.cukes</groupId>
   <artifactId>cucumber-java</artifactId> 
   <version>1.0.2</version> 
   <scope>test</scope> 
</dependency>

步骤 5 - 添加 Cucumber-JUnit 的依赖项:这将指示 Maven,哪些 Cucumber JUnit 文件将从中央存储库下载到本地存储库。

  • 再创建一个依赖标记。

  • 在依赖标签中提供以下信息

<dependency> 
   <groupId>info.cukes</groupId> 
   <artifactId>cucumber-junit</artifactId> 
   <version>1.0.2</version> 
   <scope>test</scope> 
</dependency>

步骤 6 - 添加 JUnit 的依赖项:这将指示 Maven,哪些 JUnit 文件将从中央存储库下载到本地存储库。

  • 再创建一个依赖标记。

  • 在依赖项标记中提供以下信息。

<dependency> 
   <groupId>junit</groupId> 
   <artifactId>junit</artifactId> 
   <version>4.10</version> 
   <scope>test</scope> 
</dependency>

步骤 7 - 验证二进制文件。

  • pom.xml编辑成功后,保存。

  • 转到项目 → 清理 - 这将需要几分钟的时间。

您将能够看到 Maven 存储库,如以下屏幕截图所示。

包浏览器
  • 创建一个功能文件(稍后介绍)。

  • 创建一个步骤定义文件(稍后介绍)。

  • 创建一个 JUnit 运行程序来运行测试(稍后介绍)。

Cucumber - 小Cucumber

到目前为止,我们已经了解了 Cucumber 及其用途。它执行功能文件中定义的测试脚本(将在后续章节中介绍)。编写此可执行功能文件的语言称为Gherkin。Gherkin 是一种纯英文文本语言,它可以帮助 Cucumber 工具解释和执行测试脚本。

有人可能会认为,Cucumber 支持简单的英文文本已经讨论过很多次了,那么为什么我们需要一种单独的语言 - Gherkins。答案在于Behave驱动开发的概念。

正如前面所讨论的,我们已经看到 BDD 在创建测试脚本时融合了不同的前景。可以是开发前景、业务前景等。也就是说,在开发测试脚本时,我们需要来自不同社区的人员,如开发人员、项目经理、产品所有者和测试人员。由于这些人不属于同一类别,因此存在不使用通用语言进行测试脚本概念化的风险。这是小Cucumber的进化点。

Gherkin 提供了英文文本中的通用关键字集,不同社区的人们可以使用这些关键字,并以测试脚本的形式获得相同的输出。

例子

功能- 社交网站的登录功能。鉴于我是社交网站用户。我输入用户名作为 username1 时。输入密码为password1。然后我应该被重定向到该网站的主页。

上述场景是一个名为用户登录的功能。所有以粗体突出显示的单词都是 Gherkin 关键字。

其他几个关键字的示例 -

  • 背景
  • *
  • 场景概要
  • 例子

Gherkin 将解析步骤定义文件中编写的每个步骤(稍后介绍)。因此,功能文件中提到的步骤和步骤定义文件(稍后介绍)应该匹配。

您可以在 Package Explorer 的 Maven Dependency 文件夹中找到 Gherkin jar。它与其他 Cucumber jar 一起下载。它看起来像下面的屏幕截图 -

小Cucumber罐

Gherkin 的另一个有趣的事实是,它不仅支持英语,还支持许多其他母语,例如法语、芬兰语、印度尼西亚语、匈牙利语、印地语、乌尔都语、古吉拉特语等。

Cucumber - 特点

功能可以定义项目的独立单元或功能。让我们举一个非常常见的社交网站示例。这个产品/项目的特点如何?很少有基本特征可以确定为 -

  • 在社交网站中创建和删除用户。

  • 社交网站的用户登录功能。

  • 在社交网站上分享照片或视频。

  • 发送好友请求。

  • 登出。

到目前为止,很明显,当我们谈论 Cucumber 时,被测产品的每个独立功能都可以称为一个功能。当您开始测试时,最好的做法是在派生测试脚本之前,我们应该确定要测试的功能。

功能通常包含要测试该功能的场景列表。我们存储功能、有关功能的描述和要测试的场景的文件称为功能文件。我们将在下一章中看到有关功能文件的更多信息。

在 Gherkins 中表示正在测试的功能的关键字是“Feature”。建议的最佳做法是,在功能文件中的功能标题下方编写该功能的简短描述。这也将满足良好文档的需求。

例子

功能- 社交网站的登录功能。

如果用户名和密码正确,用户应该能够登录社交网站。

如果用户名和密码不正确,应向用户显示错误消息。

如果用户名和密码正确,用户应该导航到主页。

特征文件

编写 Cucumber 测试的文件称为功能文件。建议对于每个被测试的功能都应该有一个单独的功能文件。功能文件的扩展名需要是“.feature”。

人们可以根据需要创建任意数量的特征文件。为了拥有一个有组织的结构,每个功能都应该有一个功能文件。

例如 -

先生编号 特征 特征 文件名
1 用户登录 用户登录功能
2 分享帖子 分享帖子功能
3 创建账户 创建帐户.功能
4 删除帐户 删除账户.feature

特征名称、特征文件名的命名约定取决于个人的选择。Cucumber 中没有关于名称的基本规则。

一个简单的功能文件由以下关键字/部分组成 -

  • 功能- 被测功能的名称。

  • 描述(可选)- 描述正在测试的功能。

  • 场景- 测试场景是什么。

  • 给出- 执行测试步骤之前的先决条件。

  • When - 为了执行下一步而应匹配的特定条件。

  • 那么- 如果满足 WHEN 中提到的条件,会发生什么。

例子

功能- 用户登录社交网站。

当用户名和密码正确时,用户应该能够登录社交网站。

当用户名和密码不正确时,应向用户显示错误消息。

如果用户名和密码正确,用户应该导航到主页。

大纲- 社交网站的登录功能。

给定用户导航至 Facebook。当我输入用户名“<用户名>”和密码“<密码>”时。然后,登录应该不成功。

| username  | password  |
| username1 | password1 |

* AND关键字用于显示两个条件之间的连接。AND可以与任何其他关键字一起使用,例如GIVEN、WHENTHEN

功能文件中没有写入任何逻辑细节。

步骤定义

我们已经准备好功能文件并定义了测试场景。然而,这还不是完成的工作。Cucumber 并不真正知道对于功能文件中概述的任何特定场景要执行哪一段代码。

这需要一个中间步骤定义文件。步骤定义文件存储特征文件中定义的场景的每个步骤与要执行的函数代码之间的映射。

因此,现在当 Cucumber 执行功能文件中提到的场景的某个步骤时,它会扫描步骤定义文件并找出要调用哪个函数。

步骤定义文件示例

public void goToFacebook() { 
   driver = new FirefoxDriver(); 
   driver.navigate().to("https://www.facebook.com/"); 
} 
@When "^user logs in using Username as \"([^\"]*)\" and Password as \"([^\"]*)\"$"
public void I_enter_Username_as_and_Password_as(String arg1, String arg2) {
   driver.findElement(By.id("email")).sendKeys(arg1);
   driver.findElement(By.id("pass")).sendKeys(arg2);
   driver.findElement(By.id("u_0_v")).click(); 
} 
@Then"^login should be unsuccessful$" 
public void validateRelogin() { 
   if(driver.getCurrentUrl().equalsIgnoreCase(
      "https://www.facebook.com/login.php?login_attempt=1&lwv=110")){ 
         System.out.println("Test Pass");
   } else { 
      System.out.println("Test Failed"); 
   } 
   driver.close(); 
}

因此,对于每个函数,无论您想要在每个测试步骤(即 GIVEN/THEN/WHEN)中执行什么代码,您都可以将其编写在步骤定义文件中。确保已为每个步骤定义了代码/函数。

该函数可以是 Java 函数,我们可以使用 Java 和 Selenium 命令来自动化我们的测试步骤。

Cucumber - 场景

场景是 Gherkin 的核心结构之一。每个场景都以关键字“Scenario:”(或本地化的关键字)开头,后面跟着一个可选的场景标题。每个功能可以有一个或多个场景,每个场景都包含一个或多个步骤。一个非常简单的场景示例可以是 -

场景- 验证帮助功能。

给定用户导航至 Facebook。

当用户单击“帮助”时,将打开“帮助”页面。

考虑一种情况,我们需要多次执行测试场景。假设,我们需要确保登录功能适用于所有类型的订阅持有者。这需要多次执行登录功能场景。复制粘贴相同的步骤以便重新执行代码,似乎不是一个聪明的主意。为此,Gherkin 又提供了一种结构,即场景大纲。

场景大纲与场景结构类似;唯一的区别是提供多个输入。正如您在以下示例中看到的,测试用例保持相同且不可重复。在底部,我们为变量“用户名”和“密码”提供了多个输入值。在运行实际测试时,Cucumber 会将变量替换为提供的输入值,然后执行测试。执行 pass-1 后,测试将使用另一个输入值重新运行第二次迭代。此类变量或占位符可以用“<>”表示,同时用小Cucumber语句提及。

例子

场景大纲- 社交网站的登录功能。给定用户导航至 Facebook。

当用户使用用户名“<用户名>”和密码“<密码>”登录时,登录应该成功。

| username | password  | 
| user1    | password1 | 
| user2    | password2 |

有一些提示和技巧可以帮助您巧妙地定义 Cucumber 场景。

  • 每个步骤都应该明确定义,以免给读者造成任何混乱。

  • 不要重复测试场景,如果需要可以使用场景大纲来实现重复。

  • 以可在多个场景和场景大纲中使用的方式开发测试步骤。

  • 尽可能保持每个步骤完全独立。例如:“假设用户已登录”。这可以分为两个步骤

    • 鉴于用户输入用户名。
    • 点击登录。

Cucumber - 注释

注释是预定义的文本,具有特定的含义。它让编译器/解释器知道执行时应该做什么。Cucumber 有以下一些注释 -

  • 给定-

    • 它描述了执行测试的先决条件。

    • 示例 - 假设我是 Facebook 用户

  • -

    • 它定义任何测试场景执行的触发点。

    • 示例 - 当我输入“<用户名>”时

  • 然后-

    • 然后保存要执行的测试的预期结果。

    • 示例 - 那么登录应该成功。

  • 并且-

    • 它提供任意两个语句之间的逻辑 AND 条件。AND 可以与 GIVEN、WHEN 和 THEN 语句结合使用。

    • 示例 - 当我输入我的“<用户名>”并输入我的“<密码>”时

  • 但是-

    • 它表示任意两个语句之间的逻辑或条件。OR 可以与 GIVEN、WHEN 和 THEN 语句结合使用。

    • 示例 - 那么登录应该成功。但主页不应该丢失。

  • 场景-

    • 需要在关键字“Scenario:”之后捕获有关测试场景的详细信息

    • 示例 -

      设想:

      鉴于我是 Facebook 用户

      当我进入我的

      我输入我的

      然后登录应该成功。

      但主页不应该丢失。

  • 场景大纲- (稍后介绍)

  • 示例- (稍后介绍)

  • 背景-

    • 背景通常有关于在每个场景运行之前要设置什么的说明。然而,它在“Before”钩子之后执行(稍后介绍)。因此,当我们想要设置 Web 浏览器或想要建立数据库连接时,这非常适合用于代码。

      • 示例 -

        背景:

        前往 Facebook 主页。

示例场景

让我们自动化一个场景,以便更好地理解注释。

步骤1

创建一个名为AnnotationTest的 Maven 测试项目。

  • 转到文件 → 新建 → 其他 → Maven → Maven 项目 → 下一步。

  • 提供组 ID(组 ID 将在所有项目中唯一标识您的项目)。

  • 提供artifact Id(artifact Id是没有版本的jar的名称。您可以选择任何小写的名称)。

  • 单击“完成”。

  • 打开pom.xml -

    • 转到 Eclipse 左侧的包资源管理器。

    • 展开项目 AnnotationTest。

    • 找到 pom.xml 文件。

    • 右键单击并选择选项“使用“文本编辑器”打开”。

  • 添加 Selenium 的依赖项 - 这将指示 Maven,哪些 Selenium jar 文件将从中央存储库下载到本地存储库。

    • 在编辑模式下打开pom.xml,在项目标签内创建依赖项标签(<dependency></dependency>)。

    • 在依赖项标记内,创建依赖项标记 (<dependency></dependency>)。

    • 在依赖项标记中提供以下信息。

<dependency> 
   <groupId>org.seleniumhq.selenium</groupId> 
   <artifactId>selenium-java</artifactId> 
   <version>2.47.1</version> 
</dependency>
  • 添加 Cucumber-Java 的依赖项 - 这将指示 Maven,哪些 Cucumber 文件将从中央存储库下载到本地存储库。

    • 再创建一个依赖标记。

    • 在依赖项标记中提供以下信息。

<dependency> 
   <groupId>info.cukes</groupId> 
   <artifactId>cucumber-java</artifactId> 
   <version>1.0.2</version> 
   <scope>test</scope> 
</dependency>
  • 添加 Cucumber-JUnit 的依赖项 - 这将指示 Maven,哪些 Cucumber JUnit 文件将从中央存储库下载到本地存储库。

    • 再创建一个依赖标记。

    • 在依赖项标记中提供以下信息。

<dependency> 
   <groupId>info.cukes</groupId> 
   <artifactId>cucumber-junit</artifactId> 
   <version>1.0.2</version> 
   <scope>test</scope> 
</dependency>
  • 添加 JUnit 的依赖项 - 这将指示 Maven,哪些 JUnit 文件将从中央存储库下载到本地存储库。

    • 再创建一个依赖标记。

    • 在依赖项标记中提供以下信息。

<dependency> 
   <groupId>junit</groupId> 
   <artifactId>junit</artifactId> 
   <version>4.10</version> 
   <scope>test</scope> 
</dependency>
  • 验证二进制文件。

    • pom.xml编辑成功后,保存。

    • 转到项目 → 清理 - 这将需要几分钟的时间。

第2步

在src/test/java下创建一个名为Annotation的包

  • 选择新创建的项目。

  • 右键单击并选择“新建”。

  • 选择选项“包”。

  • 将其命名为“注释”。

  • 保存。

步骤3

创建一个名为annotation.feature的特征文件。

  • 选择并右键单击包轮廓。

  • 单击“新建”文件。

  • 为文件命名,例如outline.feature

  • 在文件中写入以下文本并保存。

Feature: annotation 
#This is how background can be used to eliminate duplicate steps 

Background: 
   User navigates to Facebook Given 
   I am on Facebook login page 

#Scenario with AND 
Scenario: 
   When I enter username as "TOM"
   And I enter password as "JERRY" 
   Then Login should fail 

#Scenario with BUT 
Scenario: 
   When I enter username as "TOM" 
   And I enter password as "JERRY" 
   Then Login should fail 
   But Relogin option should be available

步骤4

创建步骤定义文件。

  • 选择并右键单击包轮廓。

  • 单击“新建”文件。

  • 将文件名指定为annotation.java

  • 在文件中写入以下文本并保存。

package Annotation; 

import org.openqa.selenium.By; 
import org.openqa.selenium.WebDriver; 
import org.openqa.selenium.firefox.FirefoxDriver; 

import cucumber.annotation.en.Given; 
import cucumber.annotation.en.Then; 
import cucumber.annotation.en.When; 

public class annotation { 
   WebDriver driver = null; 
   @Given("^I am on Facebook login page$") 
	
   public void goToFacebook() { 
      driver = new FirefoxDriver(); 
      driver.navigate().to("https://www.facebook.com/"); 
   }
	
   @When("^I enter username as \"(.*)\"$") 
   public void enterUsername(String arg1) {   
      driver.findElement(By.id("email")).sendKeys(arg1); 
   }
	
   @When ("^I enter password as \"(.*)\"$") 
   public void enterPassword(String arg1) {
      driver.findElement(By.id("pass")).sendKeys(arg1);
      driver.findElement(By.id("u_0_v")).click(); 
   } 
	
   @Then("^Login should fail$") 
   public void checkFail() {  
      if(driver.getCurrentUrl().equalsIgnoreCase(
         "https://www.facebook.com/login.php?login_attempt=1&lwv=110")){ 
            System.out.println("Test1 Pass"); 
      } else { 
         System.out.println("Test1 Failed"); 
      } 
      driver.close(); 
   } 
	
   @Then("^Relogin option should be available$") 
   public void checkRelogin() { 
      if(driver.getCurrentUrl().equalsIgnoreCase(
         "https://www.facebook.com/login.php?login_attempt=1&lwv=110")){ 
            System.out.println("Test2 Pass"); 
      } else { 
         System.out.println("Test2 Failed"); 
      } 
      driver.close(); 
   }
} 

步骤5

创建一个运行器类文件。

  • 选择并右键单击包轮廓。

  • 单击“新建”文件。

  • 为文件命名,例如runTest.java

  • 在文件中写入以下文本并保存。

package Annotation; 

import org.junit.runner.RunWith; 
import cucumber.junit.Cucumber; 

@RunWith(Cucumber.class) 
@Cucumber.Options(format = {"pretty", "html:target/cucumber"})
 
public class runTest { 
}

步骤6

使用选项运行测试 -

  • 从包资源管理器中选择 runTest.java 文件。

  • 右键单击并选择选项“运行方式”

  • 选择 JUnit 测试。

当您运行此类文件时,您将观察到以下情况 -

  • Facebook 在新的 Firefox Web 浏览器实例中打开。

  • TOM 将作为用户名字段的输入传递。

  • JERRY 将作为密码字段的输入传递。

  • 将单击登录。

  • 浏览器上将显示有关登录失败的消息。

  • 在控制台中,您将看到打印的“Test Pass”

  • 步骤结果 1. 至 5. 将针对用户名为“”且密码为“”重新执行。

Cucumber - 场景大纲

场景大纲基本上用表中的值替换变量/关键字。表中的每一行都被视为一个场景。

让我们继续使用 Facebook 登录功能的相同示例。到目前为止,我们一直在执行一种场景:提供正确的用户名后,登录成功。现在,假设我们要检查所有三种可能的输入类型(用户名、电子邮件地址或电话号码)登录是否成功。为了实现这一点,我们需要编写三个不同的场景,其中每个场景都会随着输入类型、登录成功而变化。在这种情况下,场景将如下所示。

设想:

给定用户导航至 Facebook

当我输入正确的用户名和密码时

然后登录应该成功

设想:

给定用户导航至 Facebook

当我输入正确的电子邮件地址和密码时

然后登录应该成功

设想:

给定用户导航至 Facebook

当我输入正确的电话号码和密码时

然后登录应该成功

这里,如果我们仔细观察,对于上述三种情况:语句是相同的,只是输入参数(用户名/电子邮件地址/电话号码)发生了变化。这就是场景大纲的重要性所在。

当我们使用场景大纲定义任何场景时,我们可以指定一个测试场景,并在其底部提供许多输入。该场景将执行与提供的输入数量一样多的次数。

例子

让我们创建一个场景大纲的示例 -

步骤 1 - 创建一个名为ScenarioOutlineTest的 Maven 测试项目

  • 转到文件 → 新建 → 其他 → Maven → Maven 项目 → 下一步。

  • 提供组 ID(组 ID 将在所有项目中唯一标识您的项目)。

  • 提供artifact Id(artifact Id是没有版本的jar的名称。您可以选择任何小写的名称)。

  • 单击“完成”。

  • 打开pom.xml -

    • 转到 Eclipse 左侧的包资源管理器。

    • 展开项目 CucumberTest。

    • 找到 pom.xml 文件。

    • 右键单击并选择选项“使用“文本编辑器”打开”。

  • 添加 Selenium 的依赖项 - 这将指示 Maven,哪些 Selenium jar 文件将从中央存储库下载到本地存储库。

    • 在编辑模式下打开pom.xml,在项目标签内创建依赖项标签(<dependency></dependency>)。

    • 在依赖项标记内,创建依赖项标记 (<dependency></dependency>)。

    • 在依赖项标记中提供以下信息。

<dependency> 
   <groupId>org.seleniumhq.selenium</groupId> 
   <artifactId>selenium-java</artifactId> 
   <version>2.47.1</version> 
</dependency>
  • 添加Cucumber-Java的依赖:这将指示Maven,哪些Cucumber文件将从中央存储库下载到本地存储库。

    • 再创建一个依赖标记。

    • 在依赖项标记中提供以下信息。

<dependency> 
   <groupId>info.cukes</groupId> 
   <artifactId>cucumber-java</artifactId> 
   <version>1.0.2</version> 
   <scope>test</scope> 
</dependency>
  • 添加Cucumber-JUnit的依赖:这将指示Maven,哪些Cucumber JUnit文件将从中央存储库下载到本地存储库。

    • 再创建一个依赖标记。

    • 在依赖项标记中提供以下信息。

<dependency> 
   <groupId>info.cukes</groupId> 
   <artifactId>cucumber-junit</artifactId> 
   <version>1.0.2</version> 
   <scope>test</scope> 
</dependency>
  • 添加 JUnit 的依赖项 - 这将指示 Maven,哪些 JUnit 文件将从中央存储库下载到本地存储库。

    • 再创建一个依赖标记。

    • 在依赖项标记中提供以下信息。

<dependency> 
   <groupId>junit</groupId> 
   <artifactId>junit</artifactId> 
   <version>4.10</version> 
   <scope>test</scope> 
</dependency>
  • 验证二进制文件。

    • pom.xml编辑成功后,保存。

    • 转到项目 → 清理 - 这将需要几分钟的时间。

步骤 2 - 在src/test/java下创建一个名为“outline”的包

Java包

步骤 3 - 创建一个名为“outline.feature”的特征文件

  • 选择并右键单击包轮廓。

  • 单击“新建”文件。

  • 给出文件名,例如“outline.feature”

    • 在文件中写入以下文本并保存。

      特征- 场景概要

      场景大纲- 社交网站的登录功能。

      给定用户导航至 Facebook

      当我输入用户名“<用户名>”和密码“<密码>”时

      那么登录应该不成功

示例-

| username  | password  | 
| username1 | password1 | 
| username2 | password2 |

注意- 这里,示例注释描述了场景执行时要提供的输入范围。将为提供的每个输入执行测试场景。因此,在给定的示例中,测试场景将执行三次。

步骤 4 - 创建步骤定义文件。

  • 选择并右键单击包轮廓。

  • 单击“新建”文件。

  • 将文件名指定为stepdefinition.java

  • 在文件中写入以下文本并保存。

package Outline;
 
import org.openqa.selenium.By; 
import org.openqa.selenium.WebDriver; 
import org.openqa.selenium.firefox.FirefoxDriver; 

import cucumber.annotation.en.Given; 
import cucumber.annotation.en.Then; 
import cucumber.annotation.en.When; 

public class stepdefinition { 
   WebDriver driver = null; 
	
   @Given("^user navigates to facebook$") 
   public void goToFacebook() { 
      driver = new FirefoxDriver(); 
      driver.navigate().to("https://www.facebook.com/"); 
   } 
	
   @When("^I enter Username as \"([^\"]*)\" and Password as \"([^\"]*)\"$") 
   public void I_enter_Username_as_and_Password_as(String arg1, String arg2) {
      driver.findElement(By.id("email")).sendKeys(arg1);
      driver.findElement(By.id("pass")).sendKeys(arg2);
      driver.findElement(By.id("u_0_v")).click(); 
   } 
	
   @Then("^login should be unsuccessful$") 
   public void validateRelogin() { 
      if(driver.getCurrentUrl().equalsIgnoreCase(
      "https://www.facebook.com/login.php?login_attempt=1&lwv=110")){
         System.out.println("Test Pass"); 
      } else { 
         System.out.println("Test Failed"); 
      } 
      driver.close(); 
   }    
}

注意- 在上面的代码中,我们必须定义一个具有两个输入参数的函数:一个用户名,另一个用于密码。因此,对于示例标签中提供的每组输入,将执行 GIVEN、WHEN 和 THEN 组。

步骤 5 - 创建一个运行器类文件。

  • 选择并右键单击包轮廓。

  • 单击“新建”文件。

  • 给出文件名,例如runTest.java

  • 在文件中写入以下文本并保存。

package Outline; 

import org.junit.runner.RunWith; 
import cucumber.junit.Cucumber; 

@RunWith(Cucumber.class) 
@Cucumber.Options(format = {"pretty", "html:target/cucumber"})

public class runTest { }
  • 使用选项运行测试 -

    • 从包资源管理器中选择runTest.java文件。

    • 右键单击并选择“运行方式”选项。

    • 选择 JUnit 测试。

当你运行这个类文件时,你会观察到以下情况

  • Facebook 在新的 Firefox Web 浏览器实例中打开。

  • 用户名 1 和密码 1 将作为用户名和密码字段的输入传递。

  • 将单击登录。

  • 浏览器上将显示有关登录失败的消息。

  • 在控制台中,您将看到打印的“Test Pass”。

  • 对于用户名2和密码2,将重新执行步骤结果1至5。

简而言之,当场景没有变化而只是数据值发生变化时,建议使用场景大纲数据表。

Cucumber - 标签

当功能文件中只有一个、两个甚至五个场景时,这看起来很简单。然而,在现实生活中,这种情况并不会发生。对于每个正在测试的功能,我们在单个功能文件中可能有 10 个、20 个或更多数量的场景。它们可能代表不同的目的(冒烟测试/回归测试)、不同的前景(开发人员/QA/BA)、不同的状态(准备执行/正在进行中)等。如何管理如此大量的执行?

为此,Cucumber 已经提供了一种通过使用功能文件中的标签来组织场景执行的方法。我们可以使用有用的标签来定义每个场景。稍后,在运行程序文件中,我们可以决定希望 Cucumber 执行哪个特定标签(以及场景)。标签以“@”开头。在“@”之后,您可以使用任何相关文本来定义您的标签。让我们通过一个例子来理解这一点。

假设一个特征文件中有两个或多个场景。我们只想执行一种场景作为冒烟测试的一部分。因此,第一件事是识别该场景,第二件事是在场景开头用“@SmokeTest”文本对其进行标记。让我们深入研究一下 -

步骤 1 - 创建一个名为cucumberTag的 Maven 项目。

步骤 2 - 在src/test/java下创建一个名为cucumberTag的包

步骤 3 - 创建一个名为cucumberTag.feature的功能文件。

在文件中写入以下文本并保存。该功能文件包含两种场景,其中只有一种被标记为SmokeTest标签。

功能- Cucumber标签

场景大纲- 社交网站的登录功能。

给定用户导航至 Facebook

当我输入用户名“<用户名>”和密码“<密码>”时

那么登录应该不成功

例子

| username  | password  | 
| username1 | password1 | 
| username2 | password2 |

#以下场景已被标记为 SmokeTest,并且应该执行。@SmokeTest

设想:

给定用户导航至 Facebook

当我输入用户名“<>”和密码“<>”时

然后用户应该被重定向到登录重试

步骤 4 - 创建步骤定义文件。

  • 选择并右键单击包轮廓。

  • 单击“新建”文件。

  • 为文件命名,例如cucumberTag.java

  • 在文件中写入以下文本并保存。

package cucumberTag;
 
import org.openqa.selenium.By; 
import org.openqa.selenium.WebDriver; 
import org.openqa.selenium.firefox.FirefoxDriver; 

import cucumber.annotation.en.Given; 
import cucumber.annotation.en.Then; 
import cucumber.annotation.en.When; 

public class cucumberTag { 
   WebDriver driver = null; 
	
   @Given("^user navigates to facebook$") 
   public void goToFacebook() { 
      driver = new FirefoxDriver(); 
      driver.navigate().to("https://www.facebook.com/"); 
   } 
	
   @When("^I enter Username as \"([^\"]*)\" and Password as \"([^\"]*)\"$") 
   public void I_enter_Username_as_and_Password_as(String arg1, String arg2) {
      driver.findElement(By.id("email")).sendKeys(arg1);
      driver.findElement(By.id("pass")).sendKeys(arg2);
      driver.findElement(By.id("u_0_v")).click(); 
   } 
	
   @Then("^login should be unsuccessful$") 
   public void validateRelogin() { 
      if(driver.getCurrentUrl().equalsIgnoreCase(
         "https://www.facebook.com/login.php?login_attempt=1&lwv=110")){ 
            System.out.println("Test Pass"); 
      } else { 
         System.out.println("Test Failed"); 
      }
      driver.close(); 
   } 
	
   @Then("^User should be redirected to login retry$") 
   public void loginRetry() { 
      if(driver.getCurrentUrl().equalsIgnoreCase(
         "https://www.facebook.com/login.php?login_attempt=1&lwv=110")){ 
            System.out.println("Test Pass"); 
      } else { 
         System.out.println("Test Failed"); 
      } 
      driver.close(); 
   } 
}

步骤 5 - 创建一个运行器类文件。

  • 在包内创建一个名为runTest.java 的运行器类。

  • 编写以下代码。

  • 保存文件。

package cucumberTag; 

import org.junit.runner.RunWith; 
import cucumber.junit.Cucumber; 

@RunWith(Cucumber.class) 
@Cucumber.Options(format = {"pretty", "html:target/cucumber"}) 

public class runTest { }
  • 运行测试选项。

  • 右键单击并选择“运行方式”选项。

  • 选择 JUnit 测试。

当您运行此类文件时,您将观察到以下情况。

  • Facebook 在新的 Firefox Web 浏览器实例中打开。

  • 不会向用户名和密码字段提供任何值。

  • 将单击登录。

  • 将加载登录重试页面。

在特征文件中定义标签没有限制。您可以根据需要派生出要使用的标签和要执行的场景。

主要有两种类型的标签 -

  • 默认标签- 默认标签有其预定义的含义。示例@Dev、@Ignore

  • 自定义标签- 自定义标签为您提供了充分的灵活性,可以选择适当的文本来定义标签。

标签也可以在功能级别定义。在功能级别定义标签后,它可以确保该功能文件中的所有场景都继承该标签。根据场景的性质,我们可以为单个功能使用多个标签。每当 Cucumber 找到合适的调用时,就会执行特定的场景。

Cucumber 还提供了一种反转标签选择的方法。考虑到在 25 个定义的场景中,有 10 个被标记为冒烟测试。我们只需要执行回归测试场景。

为此,我们可以在 JUnit 运行程序类中使用“~”来排除冒烟测试场景。它将如下所示。

@RunWith(Cucumber.class) 
@Cucumber.Options(format = {"pretty", "html:target/cucumber"}, 
   tags = {"~@SmokeTest"})
	
public class runTest { }

在定义多个标签的同时,我们还可以定义逻辑或/与逻辑与运算。

  • 在运行器类中定义逻辑或 - @dev,@wip - 它表示需要执行与任何此标签匹配的场景。

  • 在运行器类中定义逻辑或 - [@dev,~@wip] -它表示需要执行与这两个标签匹配的场景。

Cucumber - 数据表

在从事自动化工作时,我们可能会遇到各种各样的场景。每个场景都有不同的含义和需求。

从一开始,我们就以社交网站的登录功能为例,其中我们只需要传递两个输入参数。让我们想想更多的可能性。“新用户注册”功能怎么样?通常,在社交网站注册新用户时可以输入哪些参数?像下面这样 -

  • 用户名
  • 电子邮件地址
  • 密码
  • 重新输入密码
  • 出生日期
  • 性别
  • 电话号码

功能- 新用户注册。

验证输入错误后新用户注册是否成功。

鉴于我正在新用户注册页面上。

当我输入用户名和电子邮件地址作为电子邮件地址和密码作为,并重新输入密码作为和出生日期作为和性别作为和电话号码作为然后用户注册应该不成功。

乍一看有点乱。那么,有没有更好的方法来管理如此大的输入呢?答案可以是“数据表”。数据表是为单个标签提供的一组输入。该标签可以是 GIVEN、WHEN 或 THEN。

让我们借助数据表来编写上述场景,如下所示:

鉴于我在新用户注册页面上

当我在页面上输入有效数据时

| Fields                 | Values              |
| First Name             | Tom                 |
| Last Name              | Kenny               |
| Email Address          | someone@someone.com |
| Re-enter Email Address | someone@someone.com |
| Password               | Password1           |
| Birthdate              | 01                  |

那么用户注册应该就成功了。

例子

让我们自动化一个数据表的示例。

步骤 1 - 创建一个名为“DataTableTest”的 Maven 测试项目。

  • 转到文件 → 新建 → 其他 → Maven → Maven 项目 → 下一步。

  • 提供组 ID(组 ID 将在所有项目中唯一标识您的项目)。

  • 提供artifact Id(artifact Id是没有版本的jar的名称。您可以选择任何小写的名称)。

  • 单击“完成”。

  • 打开 pom.xml -

    • 转到 Eclipse 左侧的包资源管理器。

    • 展开项目 CucumberTest。

    • 找到 pom.xml 文件。

    • 右键单击并选择选项“使用“文本编辑器”打开”。

  • 添加Selenium依赖:这将指示Maven,哪些Selenium jar文件将从中央存储库下载到本地存储库。

    • 在编辑模式下打开pom.xml,在项目标签内创建依赖项标签(<dependency></dependency>)。

    • 在依赖项标签内,创建依赖项标签。(<依赖项></依赖项>)。

    • 在依赖项标记中提供以下信息。

<dependency> 
   <groupId>org.seleniumhq.selenium</groupId> 
   <artifactId>selenium-java</artifactId> 
   <version>2.47.1</version> 
</dependency>
  • 添加 Cucumber-Java 的依赖项 - 这将指示 Maven,哪些 Cucumber 文件将从中央存储库下载到本地存储库。

    • 再创建一个依赖标记。

    • 在依赖项标记中提供以下信息。

<dependency> 
   <groupId>info.cukes</groupId> 
   <artifactId>cucumber-java</artifactId> 
   <version>1.0.2</version> 
   <scope>test</scope> 
</dependency>
  • 添加 Cucumber-JUnit 的依赖项 - 这将指示 Maven,哪些 Cucumber JUnit 文件将从中央存储库下载到本地存储库。

    • 再创建一个依赖标记。

    • 在依赖项标记中提供以下信息。

<dependency> 
   <groupId>info.cukes</groupId> 
   <artifactId>cucumber-junit</artifactId> 
   <version>1.0.2</version> 
   <scope>test</scope> 
</dependency>
  • 添加 JUnit 的依赖项 - 这将指示 Maven,哪些 JUnit 文件将从中央存储库下载到本地存储库。

    • 再创建一个依赖标记。

    • 在依赖标签中提供以下信息

<dependency> 
   <groupId>junit</groupId> 
   <artifactId>junit</artifactId> 
   <version>4.10</version> 
   <scope>test</scope> 
</dependency>
  • 验证二进制文件。

    • pom.xml编辑成功后,保存。

    • 转到项目 → 清理 - 这将需要几分钟的时间。

步骤 2 -在src/test/java下创建一个名为dataTable的包

步骤 3 - 创建一个功能文件。

  • 在 dataTable 包中创建一个名为dataTable .feature 的功能文件(有关更详细的步骤,请参阅场景概述部分)。

  • 写出以下文字。

    功能- 数据表

    验证输入错误后新用户注册是否成功。

    设想:

    鉴于我在新用户注册页面

    当我在页面上输入无效数据时

| Fields                 | Values              |
| First Name             | Tom                 |
| Last Name              | Kenny               |
| Email Address          | someone@someone.com |
| Re-enter Email Address | someone@someone.com |
| Password               | Password1           |
| Birthdate              | 01                  |

那么用户注册应该不成功

  • 保存文件。

步骤 4 - 创建步骤定义文件。

  • 在数据表包内创建名为“dataTable.java”的步骤定义文件(有关更详细的步骤,请参阅场景概述部分)。

  • 编写以下代码。

package dataTable; 

import java.util.List; 

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.Select;

import cucumber.annotation.en.Given; 
import cucumber.annotation.en.Then; 
import cucumber.annotation.en.When; 
import cucumber.table.DataTable; 

public class stepdefinition { 
   WebDriver driver = null;
	
   @Given("^I am on new user registration page$") 
   public void goToFacebook() { 
      //Intiate web browser instance. driver = new FirefoxDriver();
      driver.navigate().to("https://www.facebook.com/"); 
   } 
	
   @When("^I enter invalid data on the page$") 
   public void enterData(DataTable table){ 
      //Initialize data table 
      List<list> data = table.raw();
      System.out.println(data.get(1).get(1)); 
      
      //Enter data
      driver.findElement(By.name("firstname")).sendKeys(data.get(1).get(1));
      driver.findElement(By.name("lastname")).sendKeys(data.get(2).get(1));
      driver.findElement(By.name("reg_email__")).sendKeys(data.get(3).get(1));     
      driver.findElement(By.name("reg_email_confirmation__")).
         sendKeys(data.get(4).get(1)); 
      driver.findElement(By.name("reg_passwd__")).sendKeys(data.get(5).get(1)); 
      
      Select dropdownB = new Select(driver.findElement(By.name("birthday_day"))); 
      dropdownB.selectByValue("15"); 
		
      Select dropdownM = new Select(driver.findElement(By.name("birthday_month")));
      dropdownM.selectByValue("6"); 
		
      Select dropdownY = new Select(driver.findElement(By.name("birthday_year")));
      dropdownY.selectByValue("1990"); 
		
      driver.findElement(By.className("_58mt")).click(); 
      // Click submit button driver.findElement(By.name("websubmit")).click(); 
   } 
	
   @Then("^User registration should be unsuccessful$") 
   public void User_registration_should_be_unsuccessful() {
      if(driver.getCurrentUrl().equalsIgnoreCase("https://www.facebook.com/")){
         System.out.println("Test Pass"); 
      } else { 
         System.out.println("Test Failed"); 
      } 
      driver.close(); 
   } 
}
  • 保存文件。

步骤 5 - 创建一个运行器类文件。

  • 在包内创建名为 runTest.java 的运行器类。

  • 编写以下代码。

package dataTable; 

import org.junit.runner.RunWith; 
import cucumber.junit.Cucumber; 

@RunWith(Cucumber.class) 
@Cucumber.Options(format = {"pretty", "html:target/cucumber"})
 
public class runTest { }
  • 保存文件。

  • 使用选项运行测试

    • 从包资源管理器中选择 runTest.java 文件。

    • 右键单击并选择选项“运行方式”。

    • 选择 JUnit 测试。

成功执行后您可能会观察到以下情况。

  • Facebook 网站已加载。

  • 数据将在注册页面上输入。

  • 将点击提交按钮。

  • 我们会看到主页不会显示,控制台上会写上“Test Pass”。

Cucumber - 评论

注释基本上是一段用于文档目的而不是用于执行的代码。无论是步骤定义文件还是功能文件,都要使其更具可读性和理解性。因此,在文件中的适当位置使用/放置注释非常重要。这在调试代码时也很有帮助。Cucumber特征文件可以在任何地方有注释。要添加注释,我们只需要用“#”号开始语句即可。

不同的编程语言有不同的定义注释的规范。让我们看看 Cucumber 是如何处理的。

  • 步骤定义文件 - 如果您使用 Java 作为平台,则用“//”标记您的注释。

  • 功能文件 - 如果是功能文件,我们只需在开始评论之前添加 # 即可。

例子

程序中突出显示的文本指的是代码中的注释。

Feature: annotation 

#This is how background can be used to eliminate duplicate steps 
Background: 
User navigates to Facebook 
Given I am on Facebook login page 

#Scenario with AND 
Scenario: 
When I enter username as "TOM" 
And I enter password as "JERRY" 
Then Login should fail 

#Scenario with BUT 
Scenario: 
When I enter username as "TOM" 
And I enter password as "JERRY" 
Then Login should fail 
But Relogin option should be available

Cucumber - 钩子

Cucumber hook可以让我们更好的管理代码工作流程,帮助我们减少代码冗余。我们可以说这是一个看不见的步骤,它允许我们执行我们的场景或测试。

为了更好地理解这个概念,让我们举一个特征文件和步骤定义文件的例子。

给定语句中突出显示的部分实际上完成了设置 webdriver 和结束 webdriver 会话的工作。所以,它实际上与“Given statements”的本质无关,而更像是一个测试的设置。此外,如果我们考虑更广泛的前景,那么在该功能的多个场景的情况下,此 Webdriver 设置和清理将与每个给定的语句一起运行。从逻辑上讲,仅执行一次设置和清理是有意义的。

因此,为了带来优化,可以使用钩子。我们更经常使用两种类型的钩子:“Before”钩子和“After”钩子。在 Before 和 After 挂钩中定义的方法/函数/代码段始终运行,即使场景通过或失败。

顾名思义,before hook 在任何其他测试场景之前执行,而 after hook 在执行所有场景之后执行。

挂钩仅在步骤定义文件中定义。

让我们自动化一个 before 和 after hook 的例子。

步骤 1 - 创建 Maven 项目作为 hookTest,在 pom.xml 中添加必要的依赖项。

步骤 2 - 在src/test/java下创建一个名为 hookTest 的 Java 包

步骤 3 -在包下创建一个名为hookTest.java 的步骤定义文件。

package hookTest; 

import org.openqa.selenium.By; 
import org.openqa.selenium.WebDriver; 
import org.openqa.selenium.firefox.FirefoxDriver; 

import cucumber.annotation.en.Given; 
import cucumber.annotation.en.Then; 
import cucumber.annotation.en.When; 

public class hookTest {
   WebDriver driver = null; 
	
   @Before public void setUp(){ 
      driver = new FirefoxDriver(); 
   } 
	
   @Given("^user navigates to facebook$") 
   public void goToFacebook() { 
      driver.navigate().to("https://www.facebook.com/");
   } 
	
   @When("^I enter Username as \"([^\"]*)\" and Password as \"([^\"]*)\"$") 
   public void I_enter_Username_as_and_Password_as(Stri