cucumber在ruby环境下表现让人惊叹,作为BDD框架的先驱,cucumber后来被移植到了多平台,有cucumber-js以及我们今天要介绍的主角cucumber-jvm。
先来看一下cucumber,简单来说cucumber是一个测试框架,就像是juint或是rspec一样,不过cucumber遵循的是BDD的原则。
BDD就是行为驱动开发,是一种软件开发流程或者说是软件开发实践,具体学术化的东西这里就不介绍了,归根到底,cucumber具有让你用自然语言编写用例的能力。
使用自然语言编写用例有很多好处,最直观的好处就是你的客户在一定的情况下是能够看懂你的测试用例的。最为项目的最核心因素,客户决定了项目该做成什么样,具有什么功能,不需要实现哪些功能。客户是需求的源泉,如果我们的测试用例很够很好的跟需求结合起来,比如说我们用自然语言写的测试用例如果能让用户认同,那么在这种情况下,测试用例基本等同于原始的需求文档了。需求文档是开发的凭据,这样一来根据测试用例来实现具体的需求就一定是客户所希望完成的需求了,毕竟这些需求是经过用户首肯的。这样一来,我们就等同于是让测试用例驱动了开发,这就是所谓的测试驱动开发的一种不太严谨的初体验了。
cucumber就是这样一种可以把需求转换为测试用例,让测试用例即需求的测试框架。概念东西不必太多先把cucumber java跑起来再说。
万事开头难,我们以最不自然的方式开始,先苦后甜。
首先下载cucumber-java的相关jar包,我整理了一下,放到了这里。
在这里要用到命令行,我们以windows平台为例。
# 创建名为cucumber_first的文件夹
mkdir cucumber_first
cd cucumber_first
# 创建jars文件夹,把下载下来的jar包全扔进来
mkdir jars
copy where\is\your\jars\*.jars jars
# 创建features文件夹
mkdir features
# 创建step_definitions文件夹
mkdir step_definitions
# 创建implementation文件夹
mkdir implementation
稍微解释一下这几个文件夹的作用
依然在命令行里,敲下面的命令
java -cp "./jars/*" cucumber.api.cli.Main features
你会看到下面的提示
No features found at [features]
0 Scenarios
0 Steps
0m0.000s
这行命令的意思就是运行features文件夹下面所有的自然语言测试用例。显然,我们没有任何测试用例,因此cucumber提示我们No features found at [features]。
继续在命令行里奋战,我们创建1个空featrue文件
type nul > type nul > features\todo.feature
上面的命令的作用是在features文件夹下面创建名为todo.feature的文件,如果你使用的是linux系统,相应的命令就是touch features\todo.feature
我们的测试项目是实现1个超级简单的任务管理工具,简单来说就是实现1个todo list,我们可以往list里面添加任务,如果任务完成则将其置为已完成,仅此而已,小而丑。
简单来说,feature文件的内容就是我们使用自然语言编写的测试用例,是我们跟用户进行交流的文档。feature文件不是乱写的,它是有一些套路,是有规范的。简单来说,一个feature文件必须包含下面的一些内容
下面我们要为我们的任务管理工具写1个测试用例,具体内容如下
Feature: 任务管理
Scenaro: 测试完成任务
Given: 我有3个任务
Then: 我完成了1个任务
Then: 我们还剩2个任务
中英结合,是不是看起来有点怪怪的?确实如此!
cucumber支持使用40多种语言来描述feature文件,这就意味着我们可以使用中文来写feature。
下面我们用中文来重构一下
#language: zh-CN
功能:任务管理
场景: 完成1件任务
假设 我的任务清单里有3个任务
当 我完成1件任务之后
那么 我还剩下2件未完成的任务
可以看到Feature关键字在中文里可以用场景来替代,这样看起来就舒服多了。不过注意一下,上面的:
是英文的冒号,最好不要写成中文的冒号。
试着在命令行中使用下面的命令:
java -cp "./jars/*" cucumber.api.cli.Main --i18n zh-CN
该命令的输出结果就是feature文件中英文关键字的对照表。
| feature | "功能" |
| background | "背景" |
| scenario | "场景", "剧本" |
| scenario_outline | "场景大纲", "剧本大纲" |
| examples | "例子" |
| given | "* ", "假如", "假设", "假定" |
| when | "* ", "当" |
| then | "* ", "那么" |
| and | "* ", "而且", "并且", "同时" |
| but | "* ", "但是" |
| given (code) | "假如", "假设", "假定" |
| when (code) | "当" |
| then (code) | "那么" |
| and (code) | "而且", "并且", "同时" |
| but (code) | "但是" |
可以看到有些关键字对应了多种中文表达,不用困惑,这没关系,哪种表达方式用起来自然就用哪种。
是时候运行一下我们刚写的feature了。
命令行里运行
java -cp "./jars/*" cucumber.api.cli.Main features
这个命令告诉cucumber,运行所有在features文件夹下的feature文件。
该命令会输出下面的结果
1 Scenarios (1 undefined)
3 Steps (3 undefined)
0m0.000s
You can implement missing steps with the snippets below:
@假设("^我的任务清单里有(\\d+)个任务$")
public void 我的任务清单里有_个任务(int arg1) throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}
@当("^我完成(\\d+)件任务之后$")
public void 我完成_件任务之后(int arg1) throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}
@那么("^我还剩下(\\d+)件未完成的任务$")
public void 我还剩下_件未完成的任务(int arg1) throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}
逐行解释一下:
如果运行时出现乱码,也就是说cucumber无法解析feature文件的话,记得将feature文件的编码改为utf8无bom
可以看出,feature文件其实即使测试用例又是需求文档,当然了一个系统光有描述性质的测试用例和需求文档是远远不够的,下一节我们将会看到cucumber是怎样把单元测试用例和自然语言用例无缝关联的。