cucumber java从入门到精通(3)简单实现及断言
上一节里我们定义了step的java代码实现文件,step就是测试步骤及断言的集合,我们先定义出来,以后可以驱动开发以及在持续集成时重用。
这一节我们将近距离细观一下所谓的step java实现。以下面的代码片段为例:
<code class="sourceCode java hljs" style="margin:0px; display:block; overflow-x:auto; padding:5px!important; line-height:1.5!important; font-family:'Courier New',sans-serif!important; font-size:12px!important; border:1px solid rgb(204,204,204)!important; background:rgb(255,255,255)"><span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">public</span></span> <span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-class" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">class</span></span></span><span class="hljs-class" style="margin:0px; padding:0px; line-height:1.5"> <span class="hljs-title" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">TodoStep</span> </span>{ <span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">//1 </span></span>
@假设(<span class="st" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">"^我的任务清单里有(</span></span><span class="ch" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">\\</span></span><span class="st" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">d+)个任务$"</span></span>) <span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">//2 </span></span>
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">public</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">void</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="fu" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-title" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">iHaveSomeTasks</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5">(</span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">int</span></span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5"> totalTasks)</span> </span><span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">throws</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> Throwable </span>{ <span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">//3 </span></span>
<span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">// Write code here that turns the phrase above into concrete actions </span></span>
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">throw</span></span> <span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">new</span></span> <span class="fu" style="margin:0px; padding:0px; line-height:1.5">PendingException</span>(); <span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">//4 </span></span>
}
}</code>
- //1 定义了public class,这没什么好说的;
- //2 假设注解,这个注解表明下面的方法对应的也就是feature文件中
我的任务清单里有xxxx个任务
这个步骤; - //3 定义了具体实现feature文件步骤的方法,并从feature定义中取得传入参数,也就是xxxx个任务的具体值;
- //4 抛出Pending异常,表明该步骤暂未实现,但来日方长,也许有天可以实现;
cucmber执行顺序
如果你对上面的代码尚有疑问,那么是时候看一下cucumber的执行顺序了,以下面代码片段为例:
<code class="sourceCode java hljs" style="margin:0px; display:block; overflow-x:auto; padding:5px!important; line-height:1.5!important; font-family:'Courier New',sans-serif!important; font-size:12px!important; border:1px solid rgb(204,204,204)!important; background:rgb(255,255,255)"># feature
假设 我的任务清单里有<span class="dv" style="margin:0px; padding:0px; line-height:1.5">3</span>个任务 <span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">// 1</span></span>
当 我完成<span class="dv" style="margin:0px; padding:0px; line-height:1.5">1</span>件任务之后 <span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">// 2</span></span>
那么 我还剩下<span class="dv" style="margin:0px; padding:0px; line-height:1.5">2</span>件未完成的任务 <span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">//3</span></span>
# step
@假设(<span class="st" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">"^我的任务清单里有(</span></span><span class="ch" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">\\</span></span><span class="st" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">d+)个任务$"</span></span>) <span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">//4 </span></span>
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">public</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">void</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="fu" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-title" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">iHaveSomeTasks</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5">(</span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">int</span></span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5"> totalTasks)</span> </span><span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">throws</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> Throwable </span>{ <span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">//5 </span></span>
<span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">// Write code here that turns the phrase above into concrete actions </span></span>
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">throw</span></span> <span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">new</span></span> <span class="fu" style="margin:0px; padding:0px; line-height:1.5">PendingException</span>();
}
@当(<span class="st" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">"^我完成(</span></span><span class="ch" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">\\</span></span><span class="st" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">d+)件任务之后$"</span></span>) <span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">//6 </span></span>
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">public</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">void</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="fu" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-title" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">iFinishSomeTasks</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5">(</span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">int</span></span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5"> finishedTasks)</span> </span><span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">throws</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> Throwable </span>{ <span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">//7 </span></span>
<span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">// Write code here that turns the phrase above into concrete actions </span></span>
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">throw</span></span> <span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">new</span></span> <span class="fu" style="margin:0px; padding:0px; line-height:1.5">PendingException</span>();
}
@那么(<span class="st" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">"^我还剩下(</span></span><span class="ch" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">\\</span></span><span class="st" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">d+)件未完成的任务$"</span></span>) <span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">//8 </span></span>
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">public</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">void</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="fu" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-title" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">iLeftSomeTasks</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5">(</span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">int</span></span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5"> leftTasks)</span> </span><span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">throws</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> Throwable </span>{ <span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">//9 </span></span>
<span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">// Write code here that turns the phrase above into concrete actions </span></span>
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">throw</span></span> <span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">new</span></span> <span class="fu" style="margin:0px; padding:0px; line-height:1.5">PendingException</span>();
} </code>
- 当我们运行了
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文件
<code class="sourceCode java hljs" style="margin:0px; display:block; overflow-x:auto; padding:5px!important; line-height:1.5!important; font-family:'Courier New',sans-serif!important; font-size:12px!important; border:1px solid rgb(204,204,204)!important; background:rgb(255,255,255)">
@假设(<span class="st" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">"^我的任务清单里有(</span></span><span class="ch" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">\\</span></span><span class="st" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">d+)个任务$"</span></span>)
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">public</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">void</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="fu" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-title" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">iHaveSomeTasks</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5">(</span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">int</span></span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5"> totalTasks)</span> </span><span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">throws</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> Throwable </span>{
<span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">// totalTasks == 3</span></span>
TodoList todo = <span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">new</span></span> <span class="fu" style="margin:0px; padding:0px; line-height:1.5">TodoList</span>();
<span class="fu" style="margin:0px; padding:0px; line-height:1.5">assertEquals</span>(todo.<span class="fu" style="margin:0px; padding:0px; line-height:1.5">getTotalTaskCount</span>(), totalTasks);
} </code>
在这里要说明的是注解中的(\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的文件,该文件的实现是
<code class="sourceCode java hljs" style="margin:0px; display:block; overflow-x:auto; padding:5px!important; line-height:1.5!important; font-family:'Courier New',sans-serif!important; font-size:12px!important; border:1px solid rgb(204,204,204)!important; background:rgb(255,255,255)"><span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">// TodoList.java</span></span>
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">package</span> implementation;</span>
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">public</span></span> <span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-class" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">class</span></span></span><span class="hljs-class" style="margin:0px; padding:0px; line-height:1.5"> <span class="hljs-title" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">TodoList</span> </span>{
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">public</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">int</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="fu" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-title" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">getTotalTaskCount</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5">()</span> </span>{
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">return</span></span> <span class="dv" style="margin:0px; padding:0px; line-height:1.5">3</span>;
}
}</code>
下面在TodoStep.java中导入TodoList类
<code class="sourceCode java hljs" style="margin:0px; display:block; overflow-x:auto; padding:5px!important; line-height:1.5!important; font-family:'Courier New',sans-serif!important; font-size:12px!important; border:1px solid rgb(204,204,204)!important; background:rgb(255,255,255)"><span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">// TodoStep.java</span></span>
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">import</span> implementation.TodoList;</span></code>
修改一下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的数量。
重构完成以后,我们的代码如下所示
<code class="sourceCode java hljs" style="margin:0px; display:block; overflow-x:auto; padding:5px!important; line-height:1.5!important; font-family:'Courier New',sans-serif!important; font-size:12px!important; border:1px solid rgb(204,204,204)!important; background:rgb(255,255,255)"><span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">package</span> step_definitions;</span>
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">import</span> cucumber.api.java.zh_cn.*;</span>
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">import</span> cucumber.api.PendingException;</span>
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">import</span> <span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">static</span> org.junit.Assert.*;</span>
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">import</span> implementation.TodoList;</span>
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">public</span></span> <span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-class" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">class</span></span></span><span class="hljs-class" style="margin:0px; padding:0px; line-height:1.5"> <span class="hljs-title" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">TodoStep</span> </span>{
TodoList todo;
@假设(<span class="st" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">"^我的任务清单里有(</span></span><span class="ch" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">\\</span></span><span class="st" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">d+)个任务$"</span></span>)
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">public</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">void</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="fu" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-title" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">iHaveSomeTasks</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5">(</span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">int</span></span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5"> totalTasks)</span> </span><span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">throws</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> Throwable </span>{
<span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">// Write code here that turns the phrase above into concrete actions </span></span>
todo = <span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">new</span></span> <span class="fu" style="margin:0px; padding:0px; line-height:1.5">TodoList</span>();
<span class="fu" style="margin:0px; padding:0px; line-height:1.5">assertEquals</span>(todo.<span class="fu" style="margin:0px; padding:0px; line-height:1.5">getTotalTaskCount</span>(), totalTasks);
}
@当(<span class="st" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">"^我完成(</span></span><span class="ch" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">\\</span></span><span class="st" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">d+)件任务之后$"</span></span>)
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">public</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">void</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="fu" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-title" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">iFinishSomeTasks</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5">(</span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">int</span></span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5"> finishedTasks)</span> </span><span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">throws</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> Throwable </span>{
<span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">// Write code here that turns the phrase above into concrete actions </span></span>
todo.<span class="fu" style="margin:0px; padding:0px; line-height:1.5">finisheTask</span>(finishedTasks);
}
@那么(<span class="st" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">"^我还剩下(</span></span><span class="ch" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">\\</span></span><span class="st" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-string" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">d+)件未完成的任务$"</span></span>)
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">public</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">void</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="fu" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-title" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">iLeftSomeTasks</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5">(</span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">int</span></span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5"> leftTasks)</span> </span><span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">throws</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> Throwable </span>{
<span class="co" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-comment" style="color:green;margin:0px; padding:0px; line-height:1.5">// Write code here that turns the phrase above into concrete actions </span></span>
<span class="fu" style="margin:0px; padding:0px; line-height:1.5">assertEquals</span>(todo.<span class="fu" style="margin:0px; padding:0px; line-height:1.5">getRestTasksCount</span>(), leftTasks);
}
} </code>
编译一下,不出意外的失败了,没关系,我们再去重构TodoList.java文件。
我们先实现finishedTask方法,这个方法的方法体是空,表示什么都不做;
然后实现getRestTasksCount方法,这个方法简单的返回2就好;
<code class="sourceCode java hljs" style="margin:0px; display:block; overflow-x:auto; padding:5px!important; line-height:1.5!important; font-family:'Courier New',sans-serif!important; font-size:12px!important; border:1px solid rgb(204,204,204)!important; background:rgb(255,255,255)">#TodoList.<span class="fu" style="margin:0px; padding:0px; line-height:1.5">java</span>
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">package</span> implementation;</span>
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">public</span></span> <span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-class" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">class</span></span></span><span class="hljs-class" style="margin:0px; padding:0px; line-height:1.5"> <span class="hljs-title" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">TodoList</span> </span>{
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">public</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">int</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="fu" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-title" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">getTotalTaskCount</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5">()</span> </span>{
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">return</span></span> <span class="dv" style="margin:0px; padding:0px; line-height:1.5">3</span>;
}
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">public</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">void</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="fu" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-title" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">finishTask</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5">(</span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">int</span></span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5"> count)</span> </span>{
}
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">public</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="dt" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">int</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"> </span><span class="fu" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-title" style="color:#a31515;margin:0px; padding:0px; line-height:1.5">getRestTasksCount</span></span></span><span class="hljs-function" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-params" style="margin:0px; padding:0px; line-height:1.5">()</span> </span>{
<span class="kw" style="margin:0px; padding:0px; line-height:1.5"><span class="hljs-keyword" style="color:#00ff;margin:0px; padding:0px; line-height:1.5">return</span></span> <span class="dv" style="margin:0px; padding:0px; line-height:1.5">2</span>;
}
}</code>
再次运行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行为驱动开发的流程是这样的:
- Describe behaviour in plain text
- Write a step definition in Java
- Run and watch it fail
- Write code to make the step pass
- Run again and see the step pass
- Repeat 2-5 until green like a cuke
小练习:翻译上面的6句话,弄清楚具体的意思。对照教程,请指出每一步与教程中所对应的代码
我们简单实现了TodoList类,目前的TodoList类是满足我们的feature的需求的。下一节我们将增加更多的测试数据,以便完善TodoList类。