cucumber作为BDD(行为驱动测试)的自动化测试工具,可以很好的帮助进行功能测试。它将功能拆分为一个个的场景(可以理解为小功能点),每个场景内可以独立的做数据初始,然后再对初始的数据进行测试,检测是否达到预期的效果。下面将从java的角度,对cucumber的使用进行说明。(为了方便起见,这边只对代码做简单的说明,完整的代码在最后以链接的形式提供下载。)
一、例子说明
下面对职员的新增和根据年龄搜索满足条件的职员进行测试,几个类的代码如下:
首先定义的职员的model:
package com.zzq.test.cucumber.staff; import java.io.Serializable; public class Staff implements Serializable { private static final long serialVersionUID = -1617670200520139146L; private String name; private int age; private String address; public Staff(){ } public Staff(String name, int age, String address) { super(); System.out.println("init data,name:"+name+",age:"+age+",address:"+address); this.name = name; this.age = age; this.address = address; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }
紧接着写了个职员的操作类StaffManager,如下:
package com.zzq.test.cucumber.staff; import java.util.ArrayList; import java.util.List; public class StaffManger { private List<Staff> staffList = new ArrayList<Staff>(); public void addStaff(Staff staff){ staffList.add(staff); } public List<Staff> findByAge(int min,int max){ List<Staff> retList = new ArrayList<Staff>(); for(Staff staff:staffList){ if(staff.getAge()>=min&&staff.getAge()<=max){ retList.add(staff); } } return retList; } }
接着对StaffManager的测试步骤(方法)进行定义,其中@Given的部分代表为测试执行的时候会调用初始的,@Then的部分代表测试的时候会用于检验数据/逻辑是否正确:
package com.zzq.test.cucumber.staff; import java.util.List; import org.junit.Assert; import com.zzq.test.cucumber.staff.Staff; import com.zzq.test.cucumber.staff.StaffManger; import cucumber.api.java.en.Given; import cucumber.api.java.en.Then; public class StaffSteps { private StaffManger manager = new StaffManger(); @Given("姓名:(.+),年龄:(\\d+),地址:(.+)") public void addStaff(String name,int age,String address){ Staff staff = new Staff(name,age,address); manager.addStaff(staff); } @Then("年龄在(\\d+)~(\\d+)的职员有(\\d+)个") public void findByAge(int min,int max,int size){ List<Staff> list = manager.findByAge(min, max); Assert.assertEquals(list.size(), size); } }
接下来定义场景Staff.feature,Given的部分与上面步骤定义的@Given对应,通过正则表达式来匹配;Then的部分与上面的@Then部分匹配。:
Feature:测试职工相关的功能 Scenario:测试根据年龄查找职工 Given 姓名:漫天的沙,年龄:18,地址:厦门市思明区 And 姓名:小明,年龄:30,地址:北京市朝阳区 And 姓名:李雷,年龄:25,地址:漳州漳浦县 And 姓名:小红,年龄:20,地址:江西省 Then 年龄在20~30的职员有3个 Then 年龄在23~30的职员有2个
接下来写一个测试的入口类:
package com.zzq.test.cucumber.staff; import org.junit.runner.RunWith; import cucumber.api.junit.Cucumber; @RunWith(Cucumber.class) public class StaffTest { }
执行类,junit的运行结果如下:
控制台执行结果如下:
二、分析
上述的代码,首先入口类需要声明@RunWith(Cucumber.class),该类存在于cucumber-junit的jar包内,声明之后会自动搜索classpath下所有声明为@Given和@Then以及场景的文件。之后对搜索到的内容进行处理,根据@Given注解的内容到搜索到的场景文件的内容进行正则匹配,如果匹配到则调用该方法(正常情况下用于数据初始);如果为@Then注解,同样的正则匹配查找,然后根据设置的参数match groups,设置对应的参数,然后传参进行校验。需要注意以下几个事项:
(1)如果feature文件与测试的Steps类不在同个目录下,需要通过@CucumberOptions注解进行指定,否则会找不到feature文件导致用例没执行(不会报错);
(2)feature文件中的Scenario、Given、And和Then均为关键字。其中Scenario代表为场景的开始,后可以跟一句话进行描述;接下来定义Given,对数据进行初始化;接着定义Then,Then用于校验的时候使用。
完整代码:完整代码