cucumber java从入门到精通(2)用代码定义步骤

上一节里我们定义了feature文件,feature文件就是自然语言描述的用例文件,它有一定的章法,具体的潜规则是:

  • 使用Feature关键字定义定义功能名称
  • 使用Scenaio关键字定义定义测试场景名称
  • 使用Given关键字定义定义前置条件
  • 使用When关键字定义定义测试步骤
  • 使用Then关键字定义定义断言

Feature文件是测试人员与客户/产品经理进行需求交流的文档工具,定义好Feature文件以后,我们的测试功能点实际上已经是定义完成了,下面的步骤很自然就是用代码去实现这些测试点。当然这里要说明的是,我们用人肉手点这些测试功能点也是没有太大问题的,但是想一想我们所处的开发阶段,现阶段我们只有整理成feature的原始需求,我们的系统还是一穷二白,一行代码都没有,因此用手点这个万能利器我们是无法使用的了。 再来思考一下如果我们使用代码去定义测试用例有什么好处?尽管系统目前没有任何功能,但这并不能妨碍我们把自动化的测试用例给写好(很大程度上,这是自动化的单元测试用例),有了用例,我们就有了标准。在后面的流程中只要开发人员编写的代码能够跑通这些自动化用例,那么我们可以比较有信心的认为开发实现了客户/产品经理所提出的需求。另外一点就是,自动化测试用例写完是可以重复使用的,在日后的回归测试、验收测试和持续集成的过程中,这些用例将起到保障产品/代码质量的关键作用。

使用cucumber定义用例(Step)

回到命令行,我们在cucumber_first\step_definitions文件夹下新建1个名为TodoStep.java的文件

 type nul > step_definitions\TodoStep.java

文本编辑器编辑该文件。在教程的开始阶段我们并不需要使用Java IDE,因此你不需要纠结到底是使用eclipse还是intellij。在windows系统上,比较推荐的文本编辑器有Notepad++, sublime, gvim。当然人各有所其所好,选择任意一种都是可以的,不过因为sublime和gvim在设置文件编码上面没有Notepad++直观,因此对于初学者来说使用Notepad++是一种比较稳妥的解决方案。

先把上一节中cucumber提示我们的那一大串代码片段复制进TodoStep.java,然后加入包名和依赖包的导入,你的TodoStep.java文件应该是这样的:

package step_definitions;

import cucumber.api.java.zh_cn.*;
import cucumber.api.PendingException;
import static org.junit.Assert.*; public class TodoStep {
@假设("^我的任务清单里有(\\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();
}
}

看上去哪里有点奇怪。的确如此,我们的方法名是中文的,这不太符合一般的代码审美。

重构方法名及参数名

是时候重构一下方法名和参数名了。这次我们重构的驱动力有下面2个:

  • 方法名是英文会让代码看上去更整洁;
  • 给方法的参数取一个更容易理解的名称会让代码在日后更容易维护。

重构完成以后,TodoStep.java中的代码应该是这样的:

package step_definitions;

import cucumber.api.java.zh_cn.*;
import cucumber.api.PendingException;
import static org.junit.Assert.*; public class TodoStep {
@假设("^我的任务清单里有(\\d+)个任务$")
public void iHaveSomeTasks(int totalTasks) throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
} @当("^我完成(\\d+)件任务之后$")
public void iFinishSomeTasks(int finishedTasks) throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
} @那么("^我还剩下(\\d+)件未完成的任务$")
public void iLeftSomeTasks(int leftTasks) throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}
}

重构完成之后我们发现我们的代码目的现在一目了然,增加了适当的可维护性。

注意:稳妥起见,请将TodoStep.java文件的编码改为gb2312。

运行steps

运行我们刚定义的steps需要2个步骤

  • 编译TodoStep.java文件
  • 运行feature文件的同时指定与feature文件相关的step文件所在的路径

看起来有点绕,其实在命令行中不难完成

首先执行编译命令:

# windows
javac -cp "./jars/*;." step_definitions\TodoStep.java # linux or unix
# javac -cp "./jars/*:." step_definitions\TodoStep.java

注意到我们把当前路径.加到了CLASSPATH里,这个很容易漏掉。

然后运行feature文件

java -cp "./jars/*;." cucumber.api.cli.Main -g step_definitions features

-g选项告诉cucumber我们要执行的steps文件存放在哪个文件夹里。同样需要注意的是当前路径.必须放到CLASSPATH里。

如果没有错误的话,你会看到下面的信息

    java -cp "./jars/*;." cucumber.api.cli.Main -g step_definitions features
P-- 1 Scenarios (1 pending)
3 Steps (2 skipped, 1 pending)
0m0.134s cucumber.api.PendingException: TODO: implement me
at step_definitions.TodoStep.iHaveSomeTasks(TodoStep.java:11)
at ?.假设我的任务清单里有3个任务(todo.feature:6)

这个提示信息告诉我们,我们定义了1个Scenario和3个Steps,不过我们并没有实现这些。因为我们的实现方法里只是简单的抛出了1个Pending异常。

Pending异常很像是占位符,它告诉代码的维护者这个测试步骤应该实现,只是现在还没开工而已。

自动化渐进

每次都在命令行里敲一长串命令除了会让你显得技术高超手法娴熟以外其实并不是什么特别有效率的事情(忽然想起来每次在命令行里用vim编辑文件各种前后台切换时总会有人发出惊叹)。而且命令越长出错的几率越大。

为什么不让这些命令自动执行呢?

先创建1个名为compile.bat的文件,我们用批处理的方式来自动运行命令。编辑之:

type nul > compile.bat
# compile.bat
javac -cp "./jars/*;." step_definitions\TodoStep.java

再创建1个名为run.bat的文件,输入如下内容

type nul > run.bat
# run.bat
java -cp "./jars/*;." cucumber.api.cli.Main -p pretty -g step_definitions features

现在我们可以把繁冗的命令简化成下面2个简单的指令了

compile
run

如果你是在linux或unix机器上,你可以这样做

touch compile
touch run echo 'javac -cp "./jars/*:." step_definitions\TodoStep.java' > compile
echo 'java -cp "./jars/*:." cucumber.api.cli.Main -p pretty -g step_definitions features ' > run chmod +x compile
chmod +x run ./compile
./run

总结

目前为止我们知道了2件事情

  • cucumber先定义feature文件,该文件是用自然语言描述的
  • 接下来要定义feature文件对应的step文件,这一步是用代码实现的

下一节我们将实现我们的第1个cucumber step及断言

cucumber java从入门到精通(2)用代码定义步骤的更多相关文章

  1. cucumber java从入门到精通(4)Scenario Outline及数据驱动

    cucumber java从入门到精通(4)Scenario Outline及数据驱动 到目前为止,我们的TodoList类工作良好,不过离我们的预期--任务清单系统还是有不少差距,究其原因不过如下: ...

  2. cucumber java从入门到精通(3)简单实现及断言

    cucumber java从入门到精通(3)简单实现及断言 上一节里我们定义了step的java代码实现文件,step就是测试步骤及断言的集合,我们先定义出来,以后可以驱动开发以及在持续集成时重用. ...

  3. cucumber java从入门到精通(1)初体验

    cucumber java从入门到精通(1)初体验 cucumber在ruby环境下表现让人惊叹,作为BDD框架的先驱,cucumber后来被移植到了多平台,有cucumber-js以及我们今天要介绍 ...

  4. 《JAVA 从入门到精通》 - 正式走向JAVA项目开发的路

    以前很多时候会开玩笑,说什么,三天学会PHP,七天精通Nodejs,xx天学会xx ... 一般来说,这样子说的多半都带有一点讽刺的意味,我也基本上从不相信什么快速入门.我以前在学校的时候自觉过很多门 ...

  5. 《Java从入门到精通》src0-8

    public class HelloWorld { public static void main(String[] args) { System.out.println("Hello wo ...

  6. 《java从入门到精通》学习记录

    目录 <Java从入门到精通>学习记录 3 基础的基础部分: 3 一. 常量与变量 3 1. 掌握: 3 (1) .常量与变量的声明方式: 3 (2) .变量的命名规则: 3 (3) .变 ...

  7. [数据结构-平衡树]普通 FHQ_Treap从入门到精通(注释比代码多系列)

    普通 FHQ_Treap从入门到精通(注释比代码多系列) 前提说明,作者写注释太累了,文章里的部分讲解来源于Oi-wiki,并根据代码,有部分增改.本文仅仅发布于博客园,其他地方出现本文,均是未经许可 ...

  8. Java从入门到精通一步到位!

    Java作为近几年来非常火的编程语言,转行来做Java的人不计其数,但如今真正的人才仍然匮乏,所以学习Java一定要有一个系统的学习规划课程.阿里云大学帮您规划Java学习路线可以帮助您从一个小白成长 ...

  9. Java从入门到精通——基础篇之JSTL标签

    一.语言基础 EL(Expression Language)表达式,目的:为了使JSP写起来更加简单.提供了在 JSP 中简化表达式的方法. 二.分类 核心标签库:提供条件判断.属性访问.URL处理及 ...

随机推荐

  1. 电子商务 B2C 结构图【转载+整理】

    本文内容 商品展示 内容展示 订单确认 支付系统 用户中心 商品&促销 CRM 订单处理 WMS 采购管理 财务管理 报表管理 系统设置 WA系统   商品展示 按照 Ebay 内部分类,任何 ...

  2. android中RecyclerView控件的列表项横向排列

    本文是在上一篇文章的基础上做的修改:android中RecyclerView控件的使用 1.修改列表项news_item.xml:我这里是把新闻标题挪到了新闻图片的下面显示 <?xml vers ...

  3. Google Chrome Resize Plugin

    https://chrome.google.com/webstore/detail/window-resizer/kkelicaakdanhinjdeammmilcgefonfh

  4. 转:Creating a Nested ESXi 5 Environment

    http://tsmith.co/2011/creating-a-nested-esxi-5-environment/ http://tsmith.co/2012/vsphere-5-1-lab-ne ...

  5. Ubuntu/Centos 系统上安装与配置Apache

    一.在线安装: Ubuntu:sudo apt-get install apache2 Centos: sudo yum install apache2 二.安装后的位置: 1.服务地址:/etc/i ...

  6. 茶道(tea)

    #include<iostream> #include<string> #include<stdio.h> #include<algorithm> #i ...

  7. ngx_http_upstream_keepalive

    链接:http://wiki.nginx.org/HttpUpstreamKeepaliveModule 今天看了一些代码: upstream b_memc2 { server ; keepalive ...

  8. ES6学习笔记四:Proxy与Reflect

    一:Proxy 代理. ES6把代理模式做成了一个类,直接传入被代理对象.代理函数,即可创建一个代理对象,然后我们使用代理对象进行方法调用,即可调用被包装过的方法: 1)创建 var proxy = ...

  9. Java中equals()和hashCode()的关系以及重写equals()和hashCode()的重要性

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6580647.html  一:关系 如果两个对象相等(equal),它们的hashcode一定相同: 如果两个对 ...

  10. 单链表Java实现

    近期在复习基本数据结构,本文是单链表的Java实现,包含对单链表的实现插入删除查找遍历等.最后还实现了单链表的逆置. 实现了多项式相加,多项式相乘. 原文章及完整源码在这里 http://binhua ...