前言
如果你关注软件开发最佳实践方面的话题,你肯定听说过测试驱动开发(TDD - Test Driven Development) 和行为驱动开发(BDD - Behavior Driven Development)。这篇文章会为你阐述这两种模式的含义并举例,同时对二者进行比较。
测试驱动开发 (TDD)
当我第一次听到TDD这个词,从字面上理解,觉得很简单,就是用于驱动软件开发的测试。
这没有错,如果对TDD作进一步的解释,这个过程可以进一步分解为5个步骤:
- 首先,开发者在码业务前写一些测试用例
- 运行这些测试用例。结果肯定是运行失败,因为测试用例中的业务逻辑还没实现嘛
- 开发者实现测试用例中的业务逻辑
- 再运行测试用例, 如果开发者代码能力不错,这些测试用例应该可以跑通了(pass)
- 对业务代码及时重构,包括增加注释,清理重复等。因为没人比开发者自己更了解哪些代码会对哪些部分造成影响从而导致测试失败(fail)
当需要开发新需求新功能时,重复上述步骤。流程如下图所示:
TDD举例
我们通过举例来了解一下如何实践TDD。例子中的代码可以从github上获取tdd-vs-bdd。将代码clone下来,执行命令npm install && grunt
假设我们想写一个计算阶乘的函数(这是一个很刻意的例子,但是这个例子对我们指出TDD和BDD的区别很有帮助)。TDD的常用方式是运行某函数,然后断言结果满足某个值。
在阶乘的例子中,我们使用的javascript测试框架是Mocha。废话不说,上代码:
var assert = require('assert'), factorial = require('../index'); suite('Test', function (){ setup(function (){ // Create any objects that we might need }); suite('#factorial()', function (){ test('equals 1 for sets of zero length', function (){ assert.equal(1, factorial(0)); }); test('equals 1 for sets of length one', function (){ assert.equal(1, factorial(1)); }); test('equals 2 for sets of length two', function (){ assert.equal(2, factorial(2)); }); test('equals 6 for sets of length three', function (){ assert.equal(6, factorial(3)); }); }); });
显然上述测试会失败,因为我们尚未实现函数功能。所以接下来我们需要实现满足上述测试用例的阶乘函数。代码如下:
module.exports = function (n) { if (n < 0) return NaN; if (n === 0) return 1; return n * factorial(n - 1); };
-
现在我们再次运行测试用例,所有的case都跑通了! 这就是TDD的使用方式。
我们接着来学习BDD,看它与TDD有什么不同。
行为驱动开发 (BDD)
BDD是什么? 很多人都会感到很模糊。 有人说它与TDD类似,有人说它是对TDD做了扩展。
抛开晦涩的定义,我们只需要记住一点:BDD旨在消除TDD过程中可能造成的问题。
与TDD相比,BDD是通过编写行为和规范来驱动软件开发。 行为和规范可能看起来与测试非常相似,但是它们之间却有着微妙但重要的区别。
BDD举例
我们还以讲解TDD中用到的阶乘函数为例:
var assert = require('assert'), factorial = require('../index'); describe('Test', function (){ before(function(){ // Stuff to do before the tests, like imports, what not }); describe('#factorial()', function (){ it('should return 1 when given 0', function (){ factorial(0).should.equal(1); }); it('should return 1 when given 1', function (){ factorial(1).should.equal(1); }); it('should return 2 when given 2', function (){ factorial(2).should.equal(2); }); it('should return 6 when given 3', function (){ factorial(3).should.equal(6); }); }); after(function () { // Anything after the tests have finished }); });
看出TDD和BDD的区别了吗?其实就是措辞。BDD的描述采用了更加’繁琐’的描述风格,阅读BDD的测试用例就像是阅读一篇文档。
这正是为什么我说BDD旨在消除TDD过程中可能造成的问题的原因所在。BDD赋予的这种像阅读句子一样阅读测试的能力有助于带来对测试认知上的转变,有助于我们去考虑如何更好写测试。当你可以流畅的阅读自己写的测试,你自然可以写出更好更全面的测试用例。
尽管上面的举例非常简单,当我们可以看出:BDD更注重功能本身而非单纯的测试用例运行结果。这也是我们经常听到的一句关于BDD本质的另外一种表达方式:BDD帮助开发人员设计(design)软件,TDD帮助开发人员测试(test)软件。
TDD vs BDD
在TDD和BDD之间做选择不是件容易的事。这取决于开发者使用的语言是否有合适的测试框架,小组的同学们是否适应对应框架的用法等等。
有人总是声称BDD优于TDD,因为BDD有助于消除TDD开发中可能产生的问题(issue)。
BDD可能有助于防止问题,但并不能保证消除所有问题。一些由糟糕的代码结构,不好的编程实践引发的问题不可能通过BDD就可以消除的。只是如果开发者BDD测试写的很糟糕,那基本上也不可能开发出健壮的功能。
转自https://blog.csdn.net/yhc166188/article/details/102881306