目录

回顾

在上一节中,我大致的介绍了一下cucumber的特点,以及基于ruby和JavaScript下关于cucumber环境的配置,如果你还没有进行相关的了解或者环境的配置,你可以点击这里来进行了解一下

在本节中,我将借用一个场景来对cucumber的一些特点来进行描述

HelloWorld

1.cucumber的目录结构

cucumber的执行需要特定的目录结构的。我们首先需要先创建这样的一个目录结构:

mkdir HelloWorld
cd HelloWorld
mkdir features
cd features
touch hello_cucumber.feature
mkdir step_definitions
cd step_definitions
touch hello_cucumber.rb

通过上面的命令创建好如下图的目录层级结构:

在图中,HelloWorld这个目录下面包含了一个名为features目录,在features目录下面有一个名为hello_cucumber.feature的文件以及一个名为step_definitions的目录,在step_definitions这个目录下面有一个名为hello_cucumber.rb的文件。下面解释下各个目录以及文件的作用:

HelloWorld

这个根目录可以理解为工程所在的目录,存放了所有需要用到的文件和资源

features

这个目录下面包含了所有的场景文件和实现场景文件中描述的步骤文件

hello_cucumber.feature

这个文件包含了场景的描述,也就是对测试用例的描述,里面一般交代了测试的前提和测试需要的条件并且当发生某一事件的时候能够得到一个什么样的结果,这些描述一般使用很易懂的自然语言来进行描述它,所以技术或者非技术人员都能看懂

在features目录下可以包含一个或者多个feature文件,一般情况下,对于具有相同性质的测试场景会放到同一个feature文件中,以便于维护

step_definitions

这个目录包含了实现测试场景描述的步骤文件

hello_cucumber.rb

这个文件包含对应的测试场景的实现代码,这个步骤文件取决于你使用的什么语言,我这里是使用的ruby

2.代码

代码主要是包含在hello_cucumber.feature和hello_cucumber.rb文件中

hello_cucumber.feature

这里我们主要描述这样一个场景,以平常一个登陆系统来做为例子吧。在测试中的话,首先会有对这个登陆系统的描述和一些基本的需求。主要是作为一个登陆系统的使用者,希望登陆系统的运作正常。正常的使用中,一个登陆场景如下:

  前置条件:进入到登陆页面

  事件: 在用户名输入框输入正确的用户名,在密码框输入正确的密码,点击确定

  预期结果:成功登陆

这是一个比较简单的测试用例,看看在cucumber中是如何实现它的。

首先我们先要将这个用例转换成cucumber所知道的描述语言,这部分描述是在feature文件中来进行实现的。代码如下:

Feature: Login
Login system should work fine Scenario: Login with right username and right password
Given I open the login page
When I set username with a right username
And I set password with a right password
And I click the login button
Then I see login success

代码中的Feature,Scenario,Given,And,When,Then都是cucumber中的关键字,Feature说明了这个测试场景的大体情况和一些基本的描述,一般由需求人员和测试人员去完成,Scenario指明了具体场景的标题,以及这个场景是用来干什么的。Given给出了具体的测试场景的条件,When给出了事件,And表示一个连接,Then是预期的结果。在一个feature文件中可以包含多个Scenario。

hello_cucumber.rb

这个文件主要包含了feature文件中描述的场景的实现,代码如下

Given /^I open the login page$/ do
puts "open login page"
end When /^I set username with a right username$/ do
puts "set a right username"
end When /^I set password with a right password$/ do
puts "set a right password"
end When /^I click the login button$/ do
puts "click login button"
end Then /^I see login success$/ do
puts "login success"
end

在feature文件中的每一个步骤都需要一个相应的ruby代码来与之对应,如果没有对应的实现步骤,则在执行用例的时候会出现找不到步骤的异常。在feature寻找步骤的时候,是通过正则表达式来进行匹配的,step文件中的Given /^...$/会匹配feature文件中符合这个正则的步骤。这个匹配是会忽略Given  When之类的关键字的。如果在匹配的时候feature中的步骤没有找到step中对应的实现,则才执行的时候会报出忽略这一个步骤的异常而导致用户不会通过的。

3.运行用例

在命令行下进入到HelloWorld这个文件夹,然后输入命令 cucumber features/hello_cucumber.feature,结果如下:

从结果中看出,我们的用例全部的通过了。而且,我们在ruby文件(step文件)中的日志也都被打印出来了(天蓝色字)。

关于cucumber的命令,我会在后面仔细的来进行介绍的。

扩展

通过上面的例子,我们已经可以使用cucumber的基本功能去实现一些用例了。当然前提还需要你去了解一些自己熟悉的语言的一些测试框架,不然单纯的cucumber并不能起到太大的作用。

现在我们来进行扩展一下上面的需求。依旧是登录的例子。测试用例如下:

  前置条件:进入到登陆页面

  事件: 在用户名输入框输入正确的用户名,在密码框输入错误的密码,点击确定

  预期结果:成功失败

根据刚刚所说的,写下的如下的feature:

Feature: Login
Login system should work fine Scenario: Login with right username and error password
Given I open the login page
When I set username with a right username
And I set password with a error password
And I click the login button
Then I see login fail

对应的step如下:

Given /^I open the login page$/ do
puts "open login page"
end When /^I set username with a right username$/ do
puts "set a right username"
end When /^I set password with a error password$/ do
puts "set a error password"
end When /^I click the login button$/ do
puts "click login button"
end Then /^I see login success$/ do
puts "login fail"
end

代码写到这里就完成了,但是软件工程中一个重要的思想是复用,相同的东西是否能进行提取呢?在上面的2个例子中,在设置密码这个地方,步骤基本是相同的,只是输入的值不一样,我们是否可以将这2个步骤合成一个呢?答案是可以的。修改设置密码的step:

When /^I set password with a (.*) password$/ do |password|
puts "set a #{password} password"
end

经过这样的修改后发现feature中密码中输入步骤也能匹配到step对应的实现,而且能将right或者是error提取成一个参数传入到实现中。

feature中的参数化使得我们很少做很多的重复工作。

聪明的你又想起了另外的一个需求,比如我们的登录的例子需要在chrome和firefox上面去执行。也许你会想,我们直接把上面的第一步(打开浏览器进入login页)修改成匹配chrome和firefox的通用步骤,然后其他的copy一遍就ok。这样做是ok的,然而cucumber提供了一种更为聪明的方法来进行这个操作。

feature如下:

Feature: Login
Login system should work fine Scenario Outline: Login with right username and right password
Given I use <browser> open the login page
When I set username with a right username
And I set password with a right password
And I click the login button
Then I see login success Examples:
| browser |
| chrome |
| firefox |

step如下:

Given /^I use (.*) open the login page$/ do |browser|
puts "use #{browser} open login page"
end When /^I set username with a right username$/ do
puts "set a right username"
end When /^I set password with a (.*) password$/ do |password|
puts "set a #{password} password"
end When /^I click the login button$/ do
puts "click login button"
end Then /^I see login success$/ do
puts "login success"
end

在feature中,将前面Scenario改为了Scenario Outline,表示会有表格参数,参数使用<>来进行标注,在用例结束后Examples关键字中写入参数的具体值。这样后,在执行用例的时候,这个用例会被执行2次,每次执行会依次的采用Examples中的参数来进行执行,我们使用命令来执行看看结果:

从结果中可以看出我们执行了2个Scenario,打出的日志在Examples下面,第一个使用了chrome,第二个使用了firefox,和我们的预期是一样的。使用Examples能大幅的减轻我们的工作量。

在cucumber中还存在着另外一个table参数。我们看看他的使用场景。依旧是登录页,但是现在登录页和之前的不太一样,我们的系统是非常注重安全的,所以每一个用户登录的时候需要使用2个密码来进行登录,如果密码全部都正确才能登录成功。测试用例如下:

  前置条件:进入到登陆页面

  事件: 在用户名输入框输入正确的用户名,在第一个密码框输入正确的密码,在第二个密码框输入正确的密码,点击确定

  预期结果:成功登录

先看看feature:

Feature: Login
Login system should work fine Scenario: Login with right username and right password
Given I open the login page
When I set username with a right username
And I set password
| id | value |
| password1 | value1 |
| password2 | value2 |
And I click the login button
Then I see login success

在看看step:

Given /^I open the login page$/ do
puts "open login page"
end When /^I set username with a right username$/ do
puts "set a right username"
end When /^I set password/ do |table|
table.hashes.each do |item|
puts "set #{item["id"]} to #{item["value"]}"
end
end When /^I click the login button$/ do
puts "click login button"
end Then /^I see login success$/ do
puts "login success"
end

在feature中,我们也使用了一个表格的形式,在step中可以通过一个参数直接获取到这个表格中的所有的参数,并且将他们存入到了hash中,而我们可以对这个hash进行操作,然后获取我们想要的值。

执行用例后如下:

可以看到结果和我们想要的是一样的。

在cucumber中有时候还会使用到步骤的组合。依旧采用登录这个例子。他里面所有的feature和使用的第一个例子一样。我们仔细想想里面的步骤中的第一步(打开登录页面),它实际是由打开浏览器和跳转到登录页面这2个步骤实现的,现在我们不改变feature,看看step中如何把这一步分解成为2步:

Given /^I open the login page$/ do
steps %{
Given I launch the browser
And I go to login page
}
end When /^I set username with a right username$/ do
puts "set a right username"
end When /^I set password with a right password/ do
puts "set a right password"
end When /^I click the login button$/ do
puts "click login button"
end Then /^I see login success$/ do
puts "login success"
end Given /^I launch the browser$/ do
puts "launch browser"
end Given /^I go to login page$/ do
puts "go to login page"
end

在上面的step中,我们将之前的一步分解成了2步,这2步又被另外的一个step所调用。你也可以用下面的方式来实现它:

Given /^I open the login page$/ do
step "I launch the browser"
step "I go to login page"
end

看看执行的结果:

结果如我们所预期的一样。

关于cucumber的基本语法就讲到这里了,如果感觉我有漏掉的希望大家可以提出。

Cucumber(2)——目录结构以及基本语法的更多相关文章

  1. II、Vue的项目目录结构 一些语法

    Vue目录结构 这是某闭源项目的web端目录结构: 目录解析: -目录/文件 - build 项目构建(webpack)相关代码 config 配置目录.端口号:也有默认的 node_modules ...

  2. Markdown基本语法及生成目录结构的方法

    Markdown是一种纯文本格式的标记语言.通过简单的标记语法,它可以使普通文本内容具有一定的格式. 一.标题 在想要设置为标题的文字前面加#来表示一个#是一级标题,二个#是二级标题,以此类推.支持六 ...

  3. Go 项目的目录结构 及 安装技巧

    项目目录结构如何组织,一般语言都是没有规定.但 Go 语言这方面做了规定,这样可以保持一致性 1.一般的,一个 Go 项目在 GOPATH 下,会有如下三个目录: |--bin |--pkg |--s ...

  4. (五)Maven目录结构及常用命令说明

    前面提到的部分知识有涉及到Maven目录结构与Maven常用的一些命令,在这里专门给大家做个简单的介绍. 1.Maven目录结构说明 Maven总体目录结构如下图: bin目录:该目录包含了mvn运行 ...

  5. 微信小程序购物商城系统开发系列-目录结构

    上一篇我们简单介绍了一下微信小程序的IDE(微信小程序购物商城系统开发系列-工具篇),相信大家都已经蠢蠢欲试建立一个自己的小程序,去完成一个独立的商城网站. 先别着急我们一步步来,先尝试下写一个自己的 ...

  6. linux目录结构详细介绍

    目录1.树状目录结构图2./目录3./etc/目录4./usr/目录5./var/目录6./proc/目录7./dev/目录 该文章主要来自于网络进行整理.目录结构参考地址:http://www.hu ...

  7. android源码的目录结构

    android源码的目录结构 [以下网络摘抄] |-- Makefile ! l/ a5 n% S% @- `0 d# z# a$ P4 V3 o7 R|-- bionic              ...

  8. linux专题一之文件管理(目录结构、创建、查看、删除、移动)

    在linux系统中一切都是文件./ 在linux中为根目录,是一切文件的根目录.本文将通过linux系统的目录结构和与linux文件操作有关的相关命令(touch.mkdir.cp.mv.mv.les ...

  9. day 2 Linux目录结构

    Linux系统的目录结构的基本介绍: 1)在逻辑上的所有目录(包括目录下的子目录)都在最高级别的目录“/”下. 根(/)目录是Linux系统中所有目录的起始点(顶点),根下面的目录及子目录是一个有层次 ...

随机推荐

  1. 动态规划-买卖股票的最佳时机 V

    2020-03-11 18:19:00 问题描述: 给出一个股票n天的价格,每天最多只能进行一次交易,可以选择买入一支股票或卖出一支股票或放弃交易,输出能够达到的最大利润值 样例 样例 1: 给出 ` ...

  2. 翻转-Flip Columns For Maximum Number of Equal Rows

    2020-02-20 11:00:06 问题描述: 问题求解: 翻转题一个常见的思路就是站在结束的状态来反推最初的状态,本题的解题思路就是站在结束的时候的状态来进行反推. 如果在最终的状态i-row是 ...

  3. Xamarin.Forms读取并展示Android和iOS通讯录 - TerminalMACS客户端

    Xamarin.Forms读取并展示Android和iOS通讯录 - TerminalMACS客户端 本文同步更新地址: https://dotnet9.com/11520.html https:// ...

  4. 最通俗易懂的 HashMap 源码分析解读

    HashMap 作为最常用的集合类之一,有必要深入浅出的了解一下.这篇文章会深入到 HashMap 源码,刨析它的存储结构以及工作机制. 1. HashMap 的存储结构 HashMap 的数据存储结 ...

  5. Python IDE ——Anaconda+PyCharm的安装与配置

    一 前言 最近莫名其妙地想学习一下Python,想着利用业余时间学习一下机器学习(或许仅仅是脑子一热吧).借着研究生期间对于PyCharm安装的印象,在自己的电脑上重新又安装了一遍.利用周末的一点时间 ...

  6. 添加windows开机自启动项

    windows系统下我们最常用的是禁用启动项,但如果程序不在自启动列表里面,如何添加程序启动呢. 其实也很简单,首先找到windows启动路径C:\Users\NL\AppData\Roaming\M ...

  7. Spring 事务注意事项

    使用事务注意事项 1,事务是程序运行如果没有错误,会自动提交事物,如果程序运行发生异常,则会自动回滚. 如果使用了try捕获异常时.一定要在catch里面手动回滚. 事务手动回滚代码 Transact ...

  8. A 大地魂力

    时间限制 : - MS   空间限制 : - KB  评测说明 : 1s,256m 问题描述 奶牛贝西认为,要改变世界,就必须吸收大地的力量,贝西把大地的力量称为魂力.要吸取大地的魂力就需要在地上开出 ...

  9. 关于C#三层架构增删改查中的“查询”问题

    序:问题总是反复出现,可能只是一个小小的问题,但是就像肉中刺. 问题: 关于“姓名”字段的拼接问题 姓名字段的拼接:this.Repeater1.DataSource = db.GetList(&qu ...

  10. 201771010108 -韩腊梅-java学习进度表

    2018面向对象程序设计(Java)课程进度表 周次 (阅读/编写)代码行数  发布博文量/评论他人博文数量  课余学习时间(小时)  学习收获最大的程序阅读或编程任务 1 30/40 1/0 8   ...