TDD的由来
测试驱动开发(Test Driven Development, TDD)的想法来自于极限编程(Extreme Programming,XP)。XP始于1999年,以测试为先为理念。因为缺少工具的支持,XP一开始不温不火,直到Junit问世,XP才得到广泛推广。坊间传言,Junit是Kent Beck和Eric Gamma两位大牛在飞机上无聊了写着玩儿弄出来的。到了03年,XP的测试优先进化成TDD,即:
● 每写一段代码之前,先写一个单元测试
● 在单元测试可以运行并失败后,编写代码
● 待到代码可以使之前的测试通过后,编码完成
● 在保持测试通过情况下,重构代码
ruby语言下TDD的例子:
我希望实现一个点,即用x,y初始化它的坐标,并且对异常值进行报错。测试为先:
class TC_Point < Test::Unit::TestCase |
02 | @@valid_points = [[ 1 , 2 ], [ 0 , 0 ]] |
03 | @@invalid_points = [[ nil , 3 ], [ 3 , nil ], [ 1 , - 2 ], [- 1 , 2 ], [ 1 . 5 , 2 ], [ 35 , 5 . 66778 ]] |
05 | @@valid_points . each do |point| |
06 | p = Point. new (point[ 0 ], point[ 1 ]) |
07 | assert(p.row == point[ 0 ]) |
08 | assert(p.column == point[ 1 ]) |
12 | @@invalid_points . each do |point| |
13 | assert_raise RuntimeError do |
14 | p = Point. new (point[ 0 ], point[ 1 ]) |
|
该代码可以运行后,再为Point这个类写实现:
02 | attr_reader :row , :column |
03 | def initialize(row, column) |
04 | if !row.is_a?( Integer ) or !column.is_a?( Integer ) |
05 | raise "row #{row} and column #{column} must be integer" |
08 | raise "row #{row} and column #{column} must be >= 0" |
|
此时,运行测试。通过测试。然后,对Point这段代码进行重构。重构,即保持原有代码行为不变,改善代码的可读性,独立性等。只要改善后的Point类可以通过测试,即,重构没有影响到原有功能。