1、什么是JBehave
JBehave是一个用java编写的BDD(Behavior-Driven-Design)框架, java界的Cucumber。(注: 1、BDD主要的目的是能够从业务领域专家的视角来编写测试用例,以解决技术人员和业务领域专家的沟通问题。2、Cucumber是基于Ruby的BDD框架)
2、JBehave的特点
1)、纯Java实现,能调用java API的地方就能使用。
2)、能够定义和执行基于文本的Story,让我们能够从用户价值出发进行开发。(BDD都是这个目的)。
3)、User stories可以放在classpath,也可通过外部URL传进来。
4)、User stories可以并发执行且能够指定并发执行的线程数。
5)、可以通过一些用户定义的信息把User Stories形成一部完整文档。
6)、通过Anotation把Story的步骤对应到Java类中,还能够把自动把Story中的String参数转换成方法对应的参数类型。(How?)
7)、基于Anotation的运行配置信息,指定Story对应的Steps类文件
8)、支持通过第三方IOC容器(Spring,Guice,PicoContainer,Weld)管理配置信息和Steps类
9)、支持通过Groovy写配置信息和Steps文件
10)、支持报表,既可以生成可读性良好的报表格式(HTML,TXT ),还支持Json,XML格式供外部程序调用。
11)、未实现的步骤会自动标记Pending
12)、支持任何语言书写Story
13)、可以使用Junit或者任何基于anotation的测试框架运行Story测试
14)、支持Maven,Ant集成,通过脚本运行BDD测试脚本。
3、JBehave的结构
Story:系统想要具有的功能
Scenario:Story描述的功能的Key-Example 。插一句,如果一个功能你不能想出一个很好的例子,那么你就需要好好想想这个功能的价值了。个人感觉,此处借用了《Specification By Examples》的思想,以实例说明功能更容易让人理解。
Steps:Scenario中描述的实例的具体执行步骤。
4、JBehave的语法
下面就是一个JBehave story的例子
上面的例子中基本上涵盖了JBehave的所有关键字(标红的词语就是JBehave的关键字)
Meta: 以键值对的方式提供一些关于Story和Scenario的标签信息,我们在运行Story的时候,可以通过这些标签作为过滤项,只运行我们想运行的信息。
Narrative: 对当前Story对应功能的一个描述,和一般Story卡上的描述差不多,In order to ….,As a ……,I want to……。
Scenario: 关于当前场景的描述
Given : 描述当前场景的Context的Step
!-- : JBehave中的注释符
When: 描述用户进行操作的Step
Then: 描述验收用户操作结果的Step,
And : Step的辅助描述关键字,跟着哪个Step就表示哪个Step的意思,如跟着When后面就表示When。
另外这个例子中未提到的关键字还有:
GivenStories: 在当前Story中依赖另一个Story。
Examples: 可以指定一系列的数据反复跑一个Scenario。
5、一个JBehave的BDD测试的实现步骤
1)、配置JBehave开发环境
2)、按照上面的语法和业务领域专家一起写文本Story。
3)、把文本Story对应到具体执行的java文件中(通过java的Anotation技术)
4)、配置JBehave的运行规则。
5)、运行测试
2)、写Story对应的Steps类
3)、配置运行环境
4)、执行结果,执行StudentStories类,即可得到运行结果。
然后在StudentSteps中增加方法
这样就可以用一句话执行之前已经实现的很多步骤。
2、Tabular parameters
表结构参数,这是一个简化和结构化参数输入的特性,我们可以在一个步骤中把需要传递的多个参数结构化的传递给Step方法。例子:
可以通过一个Table以键值对的形势来输入参数,在StudentSteps添加对应的方法来接收参数
3、Examples
Scenario多实例,这个特性主要的目的在于可以使用不同的数据反复执行一个Scenario。例子:
该实例中回使用Examples中的数据反复执行该Scenario。
4、Meta Filtering
Meta信息过滤,这个特性允许JBehave指定运行特定的Story或者Scenario。使用方法为在配置Embedder的时候添加上MetaFilter属性。
在标红的代码段中指明了只执行Meta段中属性theme为composite的Story。
5、GivenStories
Story依赖,这个特性让一个Story可以作为另一个Story的Scenario的前提条件。例子
JBehave是一个用java编写的BDD(Behavior-Driven-Design)框架, java界的Cucumber。(注: 1、BDD主要的目的是能够从业务领域专家的视角来编写测试用例,以解决技术人员和业务领域专家的沟通问题。2、Cucumber是基于Ruby的BDD框架)
2、JBehave的特点
1)、纯Java实现,能调用java API的地方就能使用。
2)、能够定义和执行基于文本的Story,让我们能够从用户价值出发进行开发。(BDD都是这个目的)。
3)、User stories可以放在classpath,也可通过外部URL传进来。
4)、User stories可以并发执行且能够指定并发执行的线程数。
5)、可以通过一些用户定义的信息把User Stories形成一部完整文档。
6)、通过Anotation把Story的步骤对应到Java类中,还能够把自动把Story中的String参数转换成方法对应的参数类型。(How?)
7)、基于Anotation的运行配置信息,指定Story对应的Steps类文件
8)、支持通过第三方IOC容器(Spring,Guice,PicoContainer,Weld)管理配置信息和Steps类
9)、支持通过Groovy写配置信息和Steps文件
10)、支持报表,既可以生成可读性良好的报表格式(HTML,TXT ),还支持Json,XML格式供外部程序调用。
11)、未实现的步骤会自动标记Pending
12)、支持任何语言书写Story
13)、可以使用Junit或者任何基于anotation的测试框架运行Story测试
14)、支持Maven,Ant集成,通过脚本运行BDD测试脚本。
3、JBehave的结构
Story:系统想要具有的功能
Scenario:Story描述的功能的Key-Example 。插一句,如果一个功能你不能想出一个很好的例子,那么你就需要好好想想这个功能的价值了。个人感觉,此处借用了《Specification By Examples》的思想,以实例说明功能更容易让人理解。
Steps:Scenario中描述的实例的具体执行步骤。
4、JBehave的语法
下面就是一个JBehave story的例子
- Meta:
- @category basic
- @color blue
- Narrative:
- In order to show the basic cart functionality
- As a user
- I want to add and remove items from the cart
- Scenario: Item can be added to cart
- Given that the cart is empty
- !-- We don't care for which item is added to the cart
- When I search for an item
- And an item is added to the cart
- Then the cart contains that item
- Scenario: Item can be removed from cart
- Given the cart contains one item
- When the item is removed
- Then the cart contents is empty
上面的例子中基本上涵盖了JBehave的所有关键字(标红的词语就是JBehave的关键字)
Meta: 以键值对的方式提供一些关于Story和Scenario的标签信息,我们在运行Story的时候,可以通过这些标签作为过滤项,只运行我们想运行的信息。
Narrative: 对当前Story对应功能的一个描述,和一般Story卡上的描述差不多,In order to ….,As a ……,I want to……。
Scenario: 关于当前场景的描述
Given : 描述当前场景的Context的Step
!-- : JBehave中的注释符
When: 描述用户进行操作的Step
Then: 描述验收用户操作结果的Step,
And : Step的辅助描述关键字,跟着哪个Step就表示哪个Step的意思,如跟着When后面就表示When。
另外这个例子中未提到的关键字还有:
GivenStories: 在当前Story中依赖另一个Story。
Examples: 可以指定一系列的数据反复跑一个Scenario。
5、一个JBehave的BDD测试的实现步骤
1)、配置JBehave开发环境
2)、按照上面的语法和业务领域专家一起写文本Story。
3)、把文本Story对应到具体执行的java文件中(通过java的Anotation技术)
4)、配置JBehave的运行规则。
5)、运行测试
6)、查看测试报告
1、配置JBehave环境。
1)、添加JBehave依赖包,基本的只需要添加jbehave-core和Junit包就足够了。
2)、配置IntelliJ的JBehave插件,详情参见https://github.com/kumaraman21/IntelliJBehave/wiki
2、实现一个JBehave的Story基本过程
JBahave的测试用例主要由3部分组成,描述测试功能的story文件,story文件对应的Steps类和基于Junit的运行配置文件。Steps类是通过Anotation和正则匹配技术把story文件中的文本Step对应到Steps类中的方法,运行配置文件的主要作用是告诉junit去哪儿找story文件和Steps文件,把其配置在同一个Context中。实现一个story的基本过程如下:
1)、写Story
- Meta:
- @author liuxianning
- @theme student
- Narrative: In order to get a new student,as a teacher, I want to add a student into the Class
- Scenario: Add a student into the class
- Given There is a student
- And his name is 'Lincoln'
- And his age is '18'
- And his hobby is 'basketball'
- And his father's name is 'Mike'
- And his mother's name is 'Mary'
- And his brother's name is 'Luis'
- When system add the student into class
- Then we can get student 'Lincoln2' from class
2)、写Story对应的Steps类
- public class StudentSteps {
- private ClassRoom classRoom;
- private Student student;
- @Given("There is a student")
- public void initStudent() {
- student = new Student();
- }
- @Given("his name is '$name'")
- public void setName(@Named("name")String name) {
- student.setName(name);
- }
- @Given("his age is '$age'")
- public void setAge(@Named("age")Integer age) {
- student.setAge(age);
- }
- @Given("his hobby is '$hobby'")
- public void setHobby(@Named("hobbu")String hobby) {
- student.setHobby(hobby);
- }
- @Given("his father's name is '$fatherName'")
- public void setFatherName(@Named("fatherName")String fatherName) {
- student.setFatherName(fatherName);
- }
- @Given("his mother's name is '$motherName'")
- public void setMotherName(@Named("motherName")String motherName) {
- student.setMotherName(motherName);
- }
- @Given("his brother's name is '$brotherName'")
- public void setBrotherName(@Named("brotherName")String brotherName) {
- student.setBrotherName(brotherName);
- }
- @When("system add the student into class")
- public void addStudentIntoClass(){
- classRoom = new ClassRoom();
- classRoom.addStudent(student);
- }
- @Then("we can get student '$studentName' from class")
- public void checkGetStudent(@Named("studentName")String studentName){
- assertThat(student, is(classRoom.getStudent(studentName)));
- }
- }
3)、配置运行环境
- public class StudentStories extends JUnitStories {
- public Configuration configuration() {
- return new MostUsefulConfiguration().useStoryLoader(new LoadFromClasspath(this.getClass()))
- .useStoryReporterBuilder(new StoryReporterBuilder().withCodeLocation(codeLocationFromClass(this.getClass())));
- }
- @Override
- protected List<String> storyPaths() {
- return new StoryFinder().findPaths(codeLocationFromClass(this.getClass()),"**/*.story","");
- }
- }
4)、执行结果,执行StudentStories类,即可得到运行结果。
1、Composite Steps
顾名思义就是能够把多个Steps组合为一个Step。例子
- Meta:
- @author liuxianning
- @theme composite
- Narrative: This story is used to show composite steps.
- Scenario: Add a student into the class
- Given There is a student with default details
- When system add the student into class
- Then we can get student 'Lincoln2' from class
然后在StudentSteps中增加方法
- @Given("There is a student with default details")
- @Composite(steps = {
- "Given his name is 'Lincoln2'",
- "Given his age is '18'",
- "Given his hobby is 'basketball'",
- "Given his father's name is 'Mike'",
- "Given his mother's name is 'Mary'",
- "Given his brother's name is 'Luis'"
- })
- public void createStudentWithDefaultDetails() {
- }
这样就可以用一句话执行之前已经实现的很多步骤。
2、Tabular parameters
表结构参数,这是一个简化和结构化参数输入的特性,我们可以在一个步骤中把需要传递的多个参数结构化的传递给Step方法。例子:
- Meta:
- @author liuxianning
- @theme table
- Narrative: In order to get a new student,as a teacher, I want to add a student into the Class
- Scenario: Add a student into the class
- Given There is a student with details:
- |name |age |hobby |father name |mother name |brother name|
- |lincoln3|18 |basketball |Mike |Mary |Luis |
- When system add the student into class
- Then we can get student 'lincoln3' from class
可以通过一个Table以键值对的形势来输入参数,在StudentSteps添加对应的方法来接收参数
- @Given("There is a student with details:$details")
- public void setDetails(@Named("details") ExamplesTable details) {
- student = new Student();
- Parameters parameters = details.getRowAsParameters(0);
- student.setName(parameters.valueAs("name",String.class));
- student.setAge(parameters.valueAs("age",Integer.class));
- student.setHobby(parameters.valueAs("hobby",String.class));
- student.setFatherName(parameters.valueAs("father name",String.class));
- student.setMotherName(parameters.valueAs("mother name",String.class));
- student.setBrotherName(parameters.valueAs("brother name",String.class));
- }
3、Examples
Scenario多实例,这个特性主要的目的在于可以使用不同的数据反复执行一个Scenario。例子:
- Meta:
- @author liuxianning
- @theme examples
- Narrative: In order to get a new student,as a teacher, I want to add a student into the Class
- Scenario: Add a student into the class
- Given There is a student
- And his name is '$name'
- And his age is '$age'
- When system add the student into class
- Then we can get student '$studentName' from class
- Examples:
- |name|age|studentName|
- |lxn1|18 |lxn1 |
- |lxn2|19 |lxn2 |
- |lxn3|20 |lxn3 |
该实例中回使用Examples中的数据反复执行该Scenario。
4、Meta Filtering
Meta信息过滤,这个特性允许JBehave指定运行特定的Story或者Scenario。使用方法为在配置Embedder的时候添加上MetaFilter属性。
- public Embedder configuredEmbedder() {
- Embedder embedder = new Embedder();
- embedder.useConfiguration(configuration());
- embedder.useCandidateSteps(candidateSteps());
- embedder.useStepsFactory(stepsFactory());
- [color=red] embedder.useMetaFilters(asList("+theme composite", "-skip"));[/color]
- return embedder;
- }
在标红的代码段中指明了只执行Meta段中属性theme为composite的Story。
5、GivenStories
Story依赖,这个特性让一个Story可以作为另一个Story的Scenario的前提条件。例子
- Meta:
- @author liuxianning
- @theme givenstories
- Narrative: In order to maintian student's info,as a teacher, I want to update a student's name
- Scenario: Add a student into the class
- GivenStories: AddStudentIntoClass.story
- Given Get student "Lincoln"
- When system Update student name to "Lin"
- Then we can get student 'Lin' from class