为什么写这篇 Helper
《The Cucumber For Java Book》这本书对于刚入门的新手来说过于不友好,
一个是 Java 世界的人不习惯用命令行来操作,大多数人是用 IDE 来写 Java,
另一个是多数时候 Cucumber 多数时候是结合 Sprint boot 等框架一起编写,很少这样Core Java直接编写,书上的编写习惯给人感觉好像来自Ruby 世界,但是 Ruby 世界的命令千锤百炼,哪里像Java命令行那么丑,
对于有些想学习 BDD 的管理型教练来说还是有点晦涩,故此有了这篇 Helper 文章。
The Helper of Cucumber for Java Book
The Cucumber For Java Book - Behavior-Driven Development for Testers and Developers
Written by Sea Rose, Matt Wynne, and Aslak Hellesoy
Source Code:https://pragprog.com/titles/srjcuc/the-cucumber-for-java-book/
Environment and Command Line
这本书是需要安装 JDK 并设置对应的环境变量的,否则没法在 terminal 里面直接运行 Java 命令,可自行 Google JDK installation, 大概要做到两个部分:
书中的例子只需要在 terminal下 cd 到对应的例子目录就可以直接运行,命令如下:
1
2
|
$ javac -cp "jars/*" step_definitions/CheckoutSteps.java
$ java -cp "jars/*:." cucumber.api.cli.Main -p progress --snippets camelcase -g step_definitions features
|
javac -cp "jars/*" step_definitions/CheckoutSteps.java
就是编译 step_definitions/CheckoutSteps.java 文件.
java -cp
即 -classpath , 指定 classpath 目录后,jvm 就会去对应目录寻找 Java 类.
cucumber.api.cli.Main
就是我们要执行的程序的入口.
-p pretty
就是告诉 cucumber 使用 pretty format 来显示输出结果.
--snippets camelcase
产生 CamelCase
风格的 snippets,可以用参数 underscore
生成 snake_case
风格的 snippets.
-g step_definitions
告诉 cucumber 去 step_definitions 目录下寻找对应的steps.
features
是指到当前目录下的 features 目录去寻找 .feature 文件.
可以先跳到 第十四章 去看完整的命令和参数描述:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
❯ java cucumber.api.cli.Main --help
Usage: java cucumber.api.cli.Main [options] [[[FILE|DIR][:LINE[:LINE]*] ]+ | @FILE ]
Options:
-g, --glue PATH Where glue code (step definitions and hooks) is loaded from.
-p, --plugin PLUGIN[:PATH_OR_URL] Register a plugin.
Built-in PLUGIN types: junit, html, pretty, progress, json, usage,
rerun. PLUGIN can also be a fully qualified class name, allowing
registration of 3rd party plugins.
-f, --format FORMAT[:PATH_OR_URL] Deprecated. Use --plugin instead.
-t, --tags TAG_EXPRESSION Only run scenarios tagged with tags matching TAG_EXPRESSION.
-n, --name REGEXP Only run scenarios whose names match REGEXP.
-d, --[no-]-dry-run Skip execution of glue code.
-m, --[no-]-monochrome Don't colour terminal output.
-s, --[no-]-strict Treat undefined and pending steps as errors.
--snippets [underscore|camelcase] Naming convention for generated snippets. Defaults to underscore.
-v, --version Print version.
-h, --help You're looking at it.
--i18n LANG List keywords for in a particular language
Run with "--i18n help" to see all languages
Feature path examples:
<path> Load the files with the extension ".feature" for the directory <path>
and its sub directories.
<path>/<name>.feature Load the feature file <path>/<name>.feature from the file system.
classpath:<path>/<name>.feature Load the feature file <path>/<name>.feature from the classpath.
<path>/<name>.feature:3:9 Load the scenarios on line 3 and line 9 in the file
<path>/<name>.feature.
@<path>/<file> Parse <path>/<file> for feature paths generated by the rerun formatter.
|
Regular Expression
正则表达式,做完就忘,触之google。
1
2
3
4
|
@Given("^the price of a \"(.*?)\" is (\\d+)c$")
public void thePriceOfAIsC(String name, int price) throws Throwable {
int bananaPrice = price;
}
|
$
匹配输入字符串的结尾位置
^
匹配输入字符串的开始位置
\
将下一个字符标记为原义字符, \"
匹配 "
, \\
匹配 \
+
加号代表前面的字符必须至少出现一次(1次或多次)
\d
是匹配一个数字(0到9)
\d+
表示一个或者多个数字
"\\d+"
是在程序字符串 ""
中,先转意\\
为\
, 然后组合出\d+
.
匹配除换行符 \n 之外的任何单字符
"(.*?)"
则是得到包含几个元素的列表,每个元素直接对应原来文本中不同的位置匹配的项
Another Alternative: Cucumber Expression
正则表达式太过繁琐,Cucumber本身提供了一种Cucumber Expression,{word}
,{string}
等等
1
2
3
4
5
6
7
8
9
|
Feature: Landing in page
Scenario: Login my account
Given I have previously created a username: kay
And I have previously created a password: okay
When I enter my username correctly
And I enter my passwrod correctly
And I click on the button "login"
Then I got a feedback "login successfully"
|
这里我用最近用nodejs写的一段BDD代码来举例几个用法,注意字符串和字面量之间的区别
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
Given("I have previously created a username: {word}", function (username) {
this.username = username;
});
Given("I have previously created a password: {word}", function (password) {
this.password = password;
});
...
When("I click on the button {string}", function (button) {
if (button === "login") {
this.isSubmit = true;
} else {
this.isSubmit = false;
}
});
|
类似的用法还有{int}
,{float}
等等,更多可以参考
https://github.com/cucumber/cucumber-expressions#readme
i18n
这本书对新手的不友好程度我感觉有五颗星吧,不只是库很旧,连java命令有些都给不全,新手几乎不太可能一直跟着书的命令跑下去,需要点前期的准备:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#在原书附带的代码里面的那个first_taste/jars 下有本书以来的Jar包添加到 CLASSPATH 里面
❯ export CLASSPATH=.:./jars/cucumber-core-1.2.0.jar:./jars/cucumber-java-1.2.0.jar:./jars/cucumber-jvm-deps-1.0.3.jar:./jars/gherkin-2.12.2.jar:./jars/junit-4.11.jar
❯ java cucumber.api.cli.Main --i18n help
ar
bg
bm
ca
...
uz
vi
zh-CN
zh-TW
# 完整的命令是这样
❯ java -cp ".:jars/*" cucumber.api.cli.Main --i18n help
|
理解了上面怎么玩的后,我们可以自己DIY一个高级版, 新建一个叫 cucumber
的文件,内容如下:
1
2
|
#!/bin/sh
java cucumber.api.cli.Main $1 $2
|
之后就能运行了
1
2
3
4
5
6
7
8
9
10
11
12
13
|
❯ chmod a+x cucumber
❯ ./cucumber --i18n help
ar
bg
bm
ca
cs
...
hr
hu
id
zh-CN
zh-TW
|
大概做两件事情
- 把Jar包加入到 CLASSPATH 里面
- 用一个Shell Script来接收命令参数并传给 java cucumber.api.cli.Main 执行
New Born : From info.cukes To io.cucumber
如果遇到编译上的兼容问题,请回想起来 info.cukes has deprated and migrated to io.cucumber.
-
试试官方的 10 minutes tutorial, 就能得到一个使用了io.cucumber + junit 4的maven工程方便后续改代码了
-
也可以试试我使用了io.cucumber 新库改的 Cucumber for Java Book 上的 pom.xml, 运行mvn package
后就会copy所有依赖的Jar在target/lib下,用这些新库去运行书上的例子就不会有那些奇奇怪怪的问题了
需要注意的是原书代码上的 import 和 Main 入口需要改成新库的
1
2
3
4
5
6
7
8
9
10
11
12
|
// import cucumber.api.java.en.*;
// import cucumber.api.PendingException;
import io.cucumber.java.PendingException;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
// cucumber.api.cli.Main
io.cucumber.core.cli.Main
|
_To be Continued …_这个人很懒,有缘再续写
Reference
info.cukes » cucumber-java
https://mvnrepository.com/artifact/info.cukes/cucumber-java
Cucumber Expression
https://github.com/cucumber/cucumber-expressions#readme
Cucumber official guide.
https://cucumber.io/docs/guides/
10 minutes official tutorial of cucumber.
https://cucumber.io/docs/guides/10-minute-tutorial/?lang=java
Gist of new pom.xml using io.cucumber.
https://gist.github.com/qzi/37813ad453b38867035729b00224c274
Copyright Notice: This page is licensed under BY-NC-ND