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

上一节里我们定义了step的java代码实现文件,step就是测试步骤及断言的集合,我们先定义出来,以后可以驱动开发以及在持续集成时重用。

这一节我们将近距离细观一下所谓的step java实现。以下面的代码片段为例:

public class TodoStep { //1
@假设("^我的任务清单里有(\\d+)个任务$") //2
public void iHaveSomeTasks(int totalTasks) throws Throwable { //3
// Write code here that turns the phrase above into concrete actions
throw new PendingException(); //4
}
}
  • //1 定义了public class,这没什么好说的;
  • //2 假设注解,这个注解表明下面的方法对应的也就是feature文件中我的任务清单里有xxxx个任务这个步骤;
  • //3 定义了具体实现feature文件步骤的方法,并从feature定义中取得传入参数,也就是xxxx个任务的具体值;
  • //4 抛出Pending异常,表明该步骤暂未实现,但来日方长,也许有天可以实现;

cucmber执行顺序

如果你对上面的代码尚有疑问,那么是时候看一下cucumber的执行顺序了,以下面代码片段为例:

# feature
假设 我的任务清单里有3个任务 // 1
当 我完成1件任务之后 // 2
那么 我还剩下2件未完成的任务 //3 # step
@假设("^我的任务清单里有(\\d+)个任务$") //4
public void iHaveSomeTasks(int totalTasks) throws Throwable { //5
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
} @当("^我完成(\\d+)件任务之后$") //6
public void iFinishSomeTasks(int finishedTasks) throws Throwable { //7
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
} @那么("^我还剩下(\\d+)件未完成的任务$") //8
public void iLeftSomeTasks(int leftTasks) throws Throwable { //9
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}
  • 当我们运行了run命令后(还记得上一节的run吗?其实就是执行了cucumber.api.cli.Main。),cucumber会去找feature文件,然后执行第1条feature语句,也就是//1
  • 执行//1的时候,cucumber会去找对应的step定义文件,寻寻觅觅的过程中,cucumber发现了对应的注解,也就是//4
  • //4告诉cucumber,下面紧接着定义的那个方法就是该feature对应的代码实现,于是cucumber再去执行//5
  • 在执行//5的时候,cucumber将3作为totalTasks这个参数传给//5
  • cucumber执行//5方法体中的内容并收到pending异常,于是该feature执行结束,转去执行下1条feature

小练习:你能自己说明//2以及//3的执行顺序吗

渐进重构之假装实现

回忆一下我们的测试目标,我们要测试一个todo list,第1步也就是在测试背景或者叫做前置条件里,我们是这样描述的

假设 我的任务清单里有3个任务 // 1

这时候不妨假设我们有个TodoList类,该类有个getTotalTaskCount()方法返回任务清单中一共有多少条任务。基于这个想法,我们重构一下TodoStep.java文件


@假设("^我的任务清单里有(\\d+)个任务$")
public void iHaveSomeTasks(int totalTasks) throws Throwable {
// totalTasks == 3
TodoList todo = new TodoList();
assertEquals(todo.getTotalTaskCount(), totalTasks);
}

在这里要说明的是注解中的(\d)表示获取feature定义中的数字字符并把该数字(int)作为totalTasks参数传入iHaveSomeTasks方法。因此totalTaks应该等于3。另外assertEquals是jUnit的断言方法

执行一下compile && run,得到下面的结果

step_definitions\TodoStep.java:11: 错误: 找不到符号
TodoList todo = new TodoList();
^
符号: 类 TodoList
位置: 类 TodoStep
step_definitions\TodoStep.java:11: 错误: 找不到符号
TodoList todo = new TodoList();
^
符号: 类 TodoList
位置: 类 TodoStep
2 个错误

我们无法编译,因为TodoList这个类并没有定义。

下面我们定义一下TodoList类。在implementation文件夹中新建1个名为TodoList.java的文件,该文件的实现是

// TodoList.java
package implementation; public class TodoList {
public int getTotalTaskCount() {
return 3;
}
}

下面在TodoStep.java中导入TodoList类

// TodoStep.java
import implementation.TodoList;

修改一下compile文件,因为这次我们需要TodoList.java文件,修改完成的版本应该是这样的

# compile
javac -cp "./jars/*;." step_definitions\TodoStep.java implementation\TodoList.java
# linux && unix
javac -cp "./jars/*:." step_definitions\TodoStep.java implementation\TodoList.java

然后运行compile && run,得到下面的结果

#language: zh-CN
功能: 任务管理 场景: 完成1件任务 # todo.feature:5
假设我的任务清单里有3个任务 # TodoStep.iHaveSomeTasks(int)
当我完成1件任务之后 # TodoStep.iFinishSomeTasks(int)
cucumber.api.PendingException: TODO: implement me
at step_definitions.TodoStep.iFinishSomeTasks(TodoStep.java:19)
at ?.当我完成1件任务之后(todo.feature:7) 那么我还剩下2件未完成的任务 # TodoStep.iLeftSomeTasks(int) 1 Scenarios (1 pending)
3 Steps (1 skipped, 1 pending, 1 passed)
0m0.128s cucumber.api.PendingException: TODO: implement me
at step_definitions.TodoStep.iFinishSomeTasks(TodoStep.java:19)
at ?.当我完成1件任务之后(todo.feature:7)

我们看到有1个step pass了,那就是我们刚定义前置条件step,所以到现在为止我们干的不错!我们有了feature文件,该文件描述了需求和测试用例,我们完成了测试step中的前置条件,并且我们实现了1个真正的TodoList类,尽管这个类目前还是嗷嗷待哺,不过当我们实现更多的step之后,TodoList类的功能会进一步完善,直到满足用户需求。实际上我们现在做的就是BDD,用测试去驱动开发。

可能有的同学会对此不屑一顾,TodoList类到目前为止只是自欺欺人的实现了1个返回int型数字3的方法,离我们所要的任务清单还相差十万八千里。其实不用担心这个,我们的TodoList类没有实现具体的功能是因为我们实现的测试步骤还不够多,我们接收到的需求还只是那么一点点,当我们实现更多步骤之后,TodoList自然会羽翼丰满。这就是所谓的最小实现原则。

渐进重构,重构剩下的2个步骤

下面我们重构剩下的2个步骤。

我们先假设TodoList有1个finishTask方法,每次调用这个方法就会完成n个任务,n从参数传入。于是剩余的任务就会减去n。

我们再假设TodoList有1个getRestTasksCount方法,调用这个方法可以获取剩下的task的数量。

重构完成以后,我们的代码如下所示

package step_definitions;

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

编译一下,不出意外的失败了,没关系,我们再去重构TodoList.java文件。

我们先实现finishedTask方法,这个方法的方法体是空,表示什么都不做;

然后实现getRestTasksCount方法,这个方法简单的返回2就好;

#TodoList.java
package implementation; public class TodoList {
public int getTotalTaskCount() {
return 3;
} public void finishTask(int count) { } public int getRestTasksCount() {
return 2;
}
}

再次运行compile && run

可以看到,我们的step全部运行通过了

#language: zh-CN
功能: 任务管理 场景: 完成1件任务 # todo.feature:5
假设我的任务清单里有3个任务 # TodoStep.iHaveSomeTasks(int)
当我完成1件任务之后 # TodoStep.iFinishSomeTasks(int)
那么我还剩下2件未完成的任务 # TodoStep.iLeftSomeTasks(int) 1 Scenarios (1 passed)
3 Steps (3 passed)
0m0.132s

总结

从这一节可以看到,我们的cucumber BDD行为驱动开发的流程是这样的:

  1. Describe behaviour in plain text
  2. Write a step definition in Java
  3. Run and watch it fail
  4. Write code to make the step pass
  5. Run again and see the step pass
  6. Repeat 2-5 until green like a cuke

小练习:翻译上面的6句话,弄清楚具体的意思。对照教程,请指出每一步与教程中所对应的代码

我们简单实现了TodoList类,目前的TodoList类是满足我们的feature的需求的。下一节我们将增加更多的测试数据,以便完善TodoList类。

cucumber java从入门到精通(3)简单实现及断言的更多相关文章

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

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

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

    cucumber java从入门到精通(2)用代码定义步骤 上一节里我们定义了feature文件,feature文件就是自然语言描述的用例文件,它有一定的章法,具体的潜规则是: 使用Feature关键 ...

  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. Java从入门到精通——基础篇之JSTL标签

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

  8. Java从入门到精通——基础篇之Servlet与JSP的区别

    一.基本概念 1.1 Servlet Servlet是一种服务器端的Java应用程序,具有独立于平台和协议的特性,可以生成动态的Web页面.它担当客户请求(Web浏览器或其他HTTP客户程序)与服务器 ...

  9. 《Java从入门到精通》学习总结3

    1. 3种构成重载的条件: 参数类型不同.参数个数不同.参数顺序不同 只有返回值类型不同并不足以区分两个方法的重载. 2. import关键字除了导入包之外,还可以导入静态成员,这是JDK 5.0以上 ...

随机推荐

  1. 【转】Java设计模式之《享元模式》及应用场景

    享元模式:“享”就是分享之意,指一物被众人共享,而这也正是该模式的终旨所在. 享元模式有点类似于单例模式,都是只生成一个对象来被共享使用.这里有个问题,那就是对共享对象的修改,为了避免出现这种情况,我 ...

  2. 微信小程序 - 3d轮播图组件(基础)

    <!-- 目前仅支持data数据源来自banner,请看测试案例 ################ 以上三种形式轮播: 1. basic 2. 3d 3. book basic即普通轮播 3d即 ...

  3. 1004: 不明飞行物(ufo)

    #include <iostream> #include <iomanip> #include <cstdlib> #include <string> ...

  4. vuejs 过渡效果

    过渡效果 https://cn.vuejs.org/v2/guide/transitions.html http://router.vuejs.org/zh-cn/advanced/transitio ...

  5. 前台登录和Token信息交互流程

    原来总是对前台登录,怎么利用token有点迷惑,后面仔细的想了一遍,把自己简单的想法记录下来,留作记录,以便后续优化 各路大神有什么看法也可以说,能更完善整个流程. 不说了,暴力的上图: 该图是出自c ...

  6. BIO、NIO和AIO的区别(简明版)

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6543960.html 一:事件分离器 在IO读写时,把 IO请求 与 读写操作 分离调配进行,需要用到事件分离 ...

  7. dubbo注册中心介绍

    作者:微子Lee链接:https://www.jianshu.com/p/2f4cfb6ed048 Dubbo的注册中心有好多种,包括Multicast.Zookeeper.Redis.Simple等 ...

  8. 〖前端开发〗HTML/CSS基础知识学习笔记

    经过一天的学习,把慕课网的HTML/CSS基础知识学完了,笔记整理: 1. 文件结构: HTML文件的固定结构: <html> <head>...</head> & ...

  9. 【BI】商务智能

    BI的定义 商务智能BI (Business Intellignece) 商务智能是涵盖性术语,包含框架.工具.数据库.分析工具.应用和方法.商务智能的主要目标是实现数据的交互,实现对数据的操作,供管 ...

  10. python模块之HTMLParser之穆雪峰的案例(理解其用法原理)

    # -*- coding: utf-8 -*- #python 27 #xiaodeng #python模块之HTMLParser之穆雪峰的案例(理解其用法原理) #http://www.cnblog ...