我们团队使用的Cucumber作为我们的功能测试框架。Cucumber是一种BDD(Behaviour driven development)测试框架。感兴趣的读者可以去Cucumber的官网了解BDD和该框架更详细的信息:点击这里。在这里我就不详细描述了。
那么这和本文要说的Cuke4Duke有什么关系呢?实际上Cucumber是ruby编写的,原生的也只对ruby编写测试提供支持。而Cuke4Duke就像是给Cucumber提供一个包装器,让你可以使用Java编写测试。后文我将交换着使用Cucumber和Cuke4Duke。
我们在使用Cuke4Duke的时候也碰到了一些问题。比如原生的Cucumber是可以通过ruby的at_exit回调,在测试跑完之后执行点代码,但是Cuke4Duke里却没有这么一个回调。Cuke4Duke里有Before和After等annotation,但是这些annotation标记的方法是在每个场景开始之前之后执行的,而没有提供整个测试跑完之后的回调方式。
所以我就想通过修改源代码的方式添加一个AfterAll的标签。为了实现这个我们得首先对Cuke4Duke以及Cucumber有个基本的了解。本文的目的就是简单的介绍下Cuke4Duke和Cucumber是个啥东西。
对于Cucumber优点我只简单描述一下:它可以更好管理测试用例,更好的协调QA和开发人员的工作(当然,我对其了解也不太深)。
举个例子,如果我们要开发一个用户登录页面,QA先写好测试用例,然后开发人员来实现。而且我们想将这些测试用例和代码很好的结合起来管理,而不是放到一个Excel文件里。如果你使用Cucumber你可以这样做:QA编写下面这样的features文件:
1: //login.feature
2:
3: Feature: 用户登录页面
4: In order 访问到需要授权的内容
5: As a 未登录用户
6: I want to 登录网站
7:
8: Scenario:登录网站
9: Given 我打开登录页面
10: And 输入用户名和密码
11: When 点击登录按钮
12: Then 登录成功,页面跳转到首页,并在右上角显示用户名
这就是个很典型的测试用例(当然,QA写的会更专业)。我们现在要的不仅是让这些测试用例躺在那儿,还要让它跑起来。让测试用例活起来。
让测试用例活起来有很多方法,但是如何将你实现测试用例的代码和上面这里写的测试用例关联起来呢?如果你使用Cucumber可以这么做:
1: public class LoginSteps{
2:
3: @Given("^我打开登录页面$")
4: public void I_open_login_page(){
5: //open login page
6: }
7:
8: @And("^输入用户名和密码$")
9: public void input_uname_and_pwd(){
10: //input uname and pwd
11: }
12:
13: @When("^点击登录按钮$")
14: public void click_login_button(){
15: //click login button
16: }
17:
18: @Then("^登录成功,页面跳转到首页,并在右上角显示用户名$")
19: public void login_success_redirect_to_homepage_show_uname(){
20: //...
21: }
22: }
这个测试执行时Cucumber就会读取feature文件,然后寻找对应的实现方法,然后执行之。如果没发现对应的实现方法它会报告某个场景没有实现。如果所有方法都实现了并执行成功,在执行的窗口上会显示前面的feature内容。如果某一条失败,会在对应的场景下输出错误信息。这对于测试用例管理是非常有用的。
不仅如此我们还可以在feature中向代码中传递参数:
1: //login.feature
2:
3: Feature: 用户登录页面
4: In order 访问到需要授权的内容
5: As a 未登录用户
6: I want to 登录网站
7:
8: Scenario Outline:登录网站
9: Given 我打开登录页面
10: And 输入<用户名>和<密码>
11: When 点击登录按钮
12: Then 登录成功,页面跳转到首页,并在右上角显示<用户名>
13:
14: Examples:
15: |用户名|密码|
16: |abc|123|
17: |bcd|456|
18: |uname|pwd|
实现:
1: public class LoginSteps{
2:
3: @Given("^我打开登录页面$")
4: public void I_open_login_page(){
5: //open login page
6: }
7:
8: @And("^输入(.*)和(.*)$")
9: public void input_uname_and_pwd(String uname, String pwd){
10: //input uname and pwd
11: }
12:
13: @When("^点击登录按钮$")
14: public void click_login_button(){
15: //click login button
16: }
17:
18: @Then("^登录成功,页面跳转到首页,并在右上角显示(.*)$")
19: public void login_success_redirect_to_homepage_show_uname(String uname){
20: //...
21: }
22: }
这样就会用Examples里指定的数据重复的测试。
Cuke4Duke里提供了Before和After标签:
1: @After
2: public void clear_cookies(){
3: //...
4: }
这样我们就可以在每个Scenario跑完之后清除浏览器的cookies,或者清理一些插入的数据等等。
Cucumber就是这么一个BDD的测试框架。当然,如果我们想进行具体的测试还需要一些别的框架的支持。比如我们要测试Web,可能就需要操作浏览器,访问页面上的HTML元素等。我们使用的是selenium。
说些题外话
下面简单的说说怎样进行这类的测试。编写这类的功能测试我们的代码里需要四类元素:
1、feature 这就是QA编写的测试用例
2、test steps 这是开发人员或QA自己用代码自动化上面编写的测试用例(可以跑的测试用例)
3、Page Object 对于Web测试中,这就是用程序代码表示的Web页面。比如上面测试登录页面,就可以有一个LoginPage class。将login以及测试中需要关注的HTML元素通过xpath等方式定位出来,并作为成员通过LoginPage暴露。
4、Fixture 在测试中可能还要准备某些数据,比如上面登录页面,我们可能要自己准备登录用户,比如往数据库里插入几条用户信息。这就是Fixture的职责。
这样划分在测试越来越多后你就会受益的。更详细的描述你可以参见InfoQ上这篇文章:点击这里。
下一篇我会介绍Cuke4Duke如何与Cucumber一起协作,然后我们尝试添加一个AfterAll标签。