目录

回顾

在上一节中,我大致的介绍了一下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. Redis 主从复制技术原理

    基于前面介绍的 Redis 内容,Redis 只能作为一个单机内存数据库,一旦服务器宕机即不能提供服务,即便能通过持久化策略重启恢复数据,往往也做不到百分之百还原.再一个就是,单机的 Redis 需要 ...

  2. Building Applications with Force.com and VisualForce(Dev401)(十八):Visualforce Pages: Introduction to Visualforce

    Dev401-020:Visualforce Pages: Introduction to Visualforce Course Objectives1.Understand the benefits ...

  3. 粒子群优化算法(PSO)之基于离散化的特征选择(FS)(四)

    作者:Geppetto 前面我们介绍了特征选择(Feature Selection,FS)与离散化数据的重要性,介绍了PSO在FS中的重要性和一些常用的方法.FS与离散化的背景,介绍了EPSO与PPS ...

  4. ArcGIS Desktop的安装

    1.双击ArcGIS Desktop安装目录下的Setup.exe. 2.点击“下一步”. 3.选择“我接受许可协议(A)”,点击“下一步”. 4.选择“完全安装”,点击“下一步”. 5.点击“更改” ...

  5. Redis这些知识你知道吗?

    1.什么是redis? Redis 是一个基于内存的高性能key-value数据库. 2.Redis的特点 Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库 ...

  6. 2.1.JVM的垃圾回收机制,判断对象是否死亡

    因为热爱,所以坚持. 文章下方有本文参考电子书和视频的下载地址哦~ 这节我们主要讲垃圾收集的一些基本概念,先了解垃圾收集是什么.然后触发条件是什么.最后虚拟机如何判断对象是否死亡. 一.前言   我们 ...

  7. 关于dll劫持我的奇思妙想(一)

    0x00  前言 前段时间在研究着windows底层的一些东西,发现这个dll劫持一直没有做过,根据倾旋师傅的视频和文章做了一系列的研究,然后就突发来了兴致研究一些dll劫持提权. 0x01   了解 ...

  8. 爬虫简介和requests模块

    目录 爬虫介绍 requests模块 requests模块 1.requests模块的基本使用 2.get 请求携带参数,调用params参数,其本质上还是调用urlencode 3.携带header ...

  9. D. Little Artem and Dance(带环模拟 + 规律)

    D. Little Artem and Dance Little Artem is fond of dancing. Most of all dances Artem likes rueda - Cu ...

  10. CyclicBarrier是如何成为一个"栅栏"的

    CyclicBarrier是一种类似于栅栏的存在,意思就是在栅栏开放之前你都只能被挡在栅栏的一侧,当栅栏移除之后,之前被挡在一侧的多个对象则同时开始动起来. 1. 如何使用CyclicBarrier ...