BDD之单元测试(二):ATDD,TDD,BDD的区别
BDD之单元测试(三):BDD的官方教程
BDD之单元测试(四):实际的项目教程
cucumber
cucumber是BDD(Behavior-driven development,行为驱动开发)的一个自动化测试的副产品。它使用自然语言来描述测试,使得非程序员可以理解他们。Gherkin是这种自然语言测试的简单语法,而Cucumber是可以执行它们的工具。附cucumber官网链接
cucumber本质上是使用根据正则表达式匹配自然语言,然后依次执行对应的方法,以达到测试的目的。
Gherkin
Gherkin是自然语言测试的简单语法。
一个完整的测试是由多个step组成的,step即最小单元,如何复用step是非常关键的问题。
多个step组成一个Scenario,即一个完整的测试case。
多个Scenario组成一个Feature,即一组相关的测试case。
关键字
- Feature:该测试文件的描述
- Scenario Outline :该测试文件中某一个场景的描述
- Given,When,Then,And,But(steps):某一个场景的具体步骤
- Example(or Scenario):某一个场景的具体入参和期望
官方教程
一、pom
<dependency><groupId>io.cucumber</groupId><artifactId>cucumber-java8</artifactId><version>4.2.0</version></dependency><dependency><groupId>io.cucumber</groupId><artifactId>cucumber-junit</artifactId><version>4.2.0</version><scope>test</scope></dependency>
二、接口
package com.example.demo.controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class CucumberController {/*** 判断今天是否是周五** @param today* @return*/@RequestMapping("/isFriday")public boolean isFriday(String today) {return "Friday".equalsIgnoreCase(today);}
}
下面需要对上面这个controller做单元测试;如果使用常规思路去写单元测试的话,应该是新建两个 @Test:
一个是传 Friday 进去,最后给断言;
一个是传 !Friday 进去,最后给断言;
该方法,代码覆盖可以实现,但是业务不清晰,我们需要去读业务代码才能知道;
如果使用BDD的话,业务代码就只有一套,我们只需要定义 入参 和 期望 即可,方便扩展,业务清晰。
三、编写 feature
我们在 test/resources/features 下面新建feature: is_it_friday_yet.feature
Feature: Is it Friday yet?Everybody wants to know when it's FridayScenario Outline: Today is or is not FridayGiven today is "<day>"When I ask whether it's Friday yetThen I should be told "<answer>"Examples:| day | answer || Friday | true || Sunday | false || anything else! | false |
Give:today is "<day>",这个 day 是参数替换
When I ask whether it's Friday yet
Then I should be told "<answer>",这个 answer 也是参数替换
下面的Examples就是定义参数的
如果 day 是Friday的话,那么结果就为true
如果 day 不是Friday的话,那么结果就为false
......
测试用例全部写在feature里面,类似黑盒,里面的业务逻辑不需要知道,只需要知道我传入什么,期望什么即可。
四、编写 Steps
package com.example.demo.controller.cucumber.a;import com.example.demo.controller.CucumberController;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;import static org.junit.Assert.*;public class CucumberControllerSteps {private String today;private boolean actualAnswer;private CucumberController cucumberController = new CucumberController();@Given("today is {string}")public void today_is(String today) {this.today = today;}@When("I ask whether it's Friday yet")public void i_ask_whether_it_s_Friday_yet() {actualAnswer = cucumberController.isFriday(today);}@Then("I should be told {string}")public void i_should_be_told(String expectAnswer) {assertEquals(Boolean.parseBoolean(expectAnswer), actualAnswer);}
}
五、编写 RunCucumberTest
package com.example.demo;import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;
import org.junit.runner.RunWith;@RunWith(Cucumber.class)
@CucumberOptions(plugin = {"pretty"}, features = {"src/test/resources/features"})
public class RunCucumberTest {
}
六、测试运行 RunCucumberTest
我们可以看到上面图中的红色部分,很符合语义和正常逻辑;
而且测试用例时,不需要改变业务代码,只需要在feature里控制入参和期望即可。
如果你的代码不能很好的适配这个方案,那很可能是代码的设计不合理。