本文共 4299 字,大约阅读时间需要 14 分钟。
行为驱动开发(Behavior-Driven Development, BDD),是一种敏捷开发的技术,想必大多数同学都对敏捷开发领域中另一技术,测试驱动开发(Test-Driven Development,TDD)较为熟悉。
TDD的思想原则是,首先先编写单元测试,当然在没有开发功能代码之前,一定是一个失败的测试;然后再编写功能代码,想方设法让测试可以通过;再重构代码去除重复的部分。
图片来自cucumber官网
TDD的思想打破了传统开发的流程,好处也不言而喻。提高代码质量,可迅速发现并定位bug。
BDD是建立在测试驱动开发基础之上,先编写验收测试,所用语言也是团队成员(业务、产品、开发、测试等)都可以读懂的实例,再进行上述TDD的流程。
图片源自《行为驱动开发课件》
如果说TDD是让我们正确的做事,那么BDD就是让我们做正确的事。
BDD目的:在业务和开发之间达成共识。
在软件项目中涉及多人紧密协作,由产品业务讲解功能需求,开发负责代码实现,测试保证软件质量,高质量的沟通对项目成功至关重要。如果在一个项目中业务人员用自己行话,开发人员用技术语言、技术思维去理解业务,在沟通过程难免出现分歧,开发人员就可能按自己的理解去实现了一个错误的功能。
如何确保达成共识?
BDD的方法:
用通用自然语言描述实例(系统行为)
团队成员使用统一、易读的语言明确实例,作为验收测试标准。一方面可以消除理解上的歧义,一方面可以激发思考没有考虑到的场景。
活文档
这里的实例是可以随时运行,反馈系统运行真实结果,如果运行失败,要么文档过时需要更新,要么系统出现问题需要修复。
BDD的实现,Cucumber是BDD的一个优秀开源框架。
Cucumber是一款协作工具。
支持多种开发语言Java C++ Ruby python等等
它是一个命令行工具。运行是从特性feature文本中解析要测试的场景scenario,每个场景由一系列的步骤step组成,cucumber一步步执行这些步骤,得到最终的测试结果。
Cucumber的使用
JavaSE(java9还不支持)
Maven 3.31以上
IntellJ IDEA 安装cucumber for java 插件
junit junit 4.11 info.cukes cucumber-java 1.2.5 info.cukes cucumber-junit 1.2.5 test
user.feature文件,功能是管理员给系统新增用户账号,并判断账号创建成功
#language:zh-CN@api@user功能:管理员给系统新增用户账号 场景大纲:创建用户账号 当 管理员新建用户账号""手机号" " 那么 他应该可以查询到该账号" " 例子: |accountName|mobile| |test|11111111111|
特性文件必须以.feature为后缀
#language:zh-CN说明使用的是中文简体语言,cucumber支持50多种语言。不注明的情况默认是英文。
通过java cucumber.api.cli.Main --i18n--help可以查支持的语言。
但由于相关jar包并没有在classpath中,执行会直接报错误: 找不到或无法加载主类 cucumber.api.cli.Main
把相关jar包放在一个jar文件夹中,创建一个cucumber.bat文件,内容如下:
java -cp "./jars/*" cucumber.api.cli.Main %*,再执行就可以正常运行了
@api@user,是标签,可以将场景归类,在执行测试时也可以方便指定执行哪个标签的场景。
查看一下中文支持的关键词
运行测试mvn clean test,cucumber会直接告诉我有1个场景没有定义,2个步骤没有定义
并且告诉需要实现哪些缺失的steps
再次运行mvn clean test,结果是 第一个步骤pending,下一步需要去实现step
@当("^管理员新建用户$") public void 管理员新建用户(Listusers) throws Throwable { for(User user:users){ apiHelper.post("/api/adduser",user); apiHelper.expectStatus(201); }
还没有去开发这个rest api服务。这里使用的spring boot框架开发rest api服务。开始采用TDD的方式,先写一个失败的测试
@RunWith(SpringRunner.class)@SpringBootTest@AutoConfigureMockMvcpublic class UserControllerTest { @Autowired private MockMvc mvc; @Test public void addUserAddsearch() throws Exception { User user = new User(); String username = "test"; user.setAccountName(username); user.setMobile("11111111111"); String userInJson = JSON.toJSONString(user); System.out.println(userInJson); mvc.perform(post("/api/adduser") .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content(userInJson)) .andDo(print()) .andExpect(status().isCreated()); }}
执行测试,断言失败返回404。
继续写rest api服务实现,运行测试,使得测试通过。
@RestControllerpublic class UserController { @Autowired private UserService userService; @RequestMapping(value = "/api/adduser", method = RequestMethod.POST, produces = "application/json") @ResponseStatus(HttpStatus.CREATED) public void create(@RequestBody User user) { userService.create(user); } }
启动spring-boot服务 mvn spring-boot:run;
再运行test工程中的bdd测试代码,这次的结果是第一步pass,第二步 pending。再按照上面的方式,继续完成第二步。最终结果2个步骤都通过。
查看测试报告
思考:
行为驱动开发能帮助团队快速构建和交付更多有价值和高质量的产品。
目前产品开发过程依然是瀑布式需求-设计-开发-测试-验收。如使用BDD的实践,我
们会有哪些改变。
参与角色 | 现在 | 未来 |
产品 | 输出需求说明书与交互文档demo | 输出用户故事地图 描述产品的用户故事 |
产品、开发、测试 | 产品需求评审 | 编写自然语言描述的特性文件(feature) 作为验收测试标准 |
开发 | 系统设计、代码实现 | 根据feature中的场景驱动开发过程, 编写单元测试,编写实现细节, 保持最简单设计,不断重构。 |
测试 | 测试用例设计 | 使用Cucumber工具, 使得feature变为可执行的程序。 |
测试 | 执行测试用例 | 以自动化验收测试作为最基础测试。 进行探索性测试及其他非功能性测试。 |
产品、开发、测试 | 文档基本在项目开始或后期没有人持续维护 | 自动化验收测试的报告永远保持最新的文档 |
想引入BDD的开发到自己的产品线开发实践中,还会有很长的路要走,中间过程免不了遇到各种阻力。
角色 | 可能的困难 |
开发 | 已经习惯性使用原有的开发模式和思维,难以接受新的思想 |
产品 | 对敏捷中的实例化需求不知如何下手 |
测试 | 要与产品开发更紧密的协助,确保feature场景的正确性、无二义性、可执行性 |
组织 | 是否允许、是否肯下决心去做新的尝试,新方式的引入是否影响现有项目进度,各种排异性是否会使项目变得更糟 |
任何一种变革都不会轻而易举地实现,是否有决心去尝试以获得更大的收益?
参考
作者:张蕊,阿里影业-测试专家 ,文章系云效微信公众号(ali_yunxiao)首发,转载需注明来源!
更多敏捷课堂内容,关注云效微信公众账号