第一章 测试自动化
优秀的程序员也会犯错。好程序员与坏程序员的差别在于好程序员借助测试来尽快的发现错误。对于一个错误,你测试的越早,你发现它的可能行就越大,你用来找到并修正它的代价也就越小。这也解释了为什么在软件发布之前才进行测试是有很大问题的。大部分的错误你根本不会捕捉到,而对于那些你捕捉到的bug,由于修复这些bug的成本是如此之高,以致你不得不对错误进行筛选,因为你不可能将它们全部修复。
与你应该已经在做的事情相比,使用PHPUnit来进行测试并非是一个完全不同的活动。它只不过是换了一种方式。其测试方法的独特之处在于,检查你的程序以期望的方式运行,运行一组测试用例,即可运行的代码片段来自动的测试软件部件(单元)的正确性。这些可运行的代码片段被称作单元测试。
在此章中,我们将从简单的打印语句为基础的测试代码过渡到全自动测试。假设我们被要求测试PHP的内建数组(array)。需要测试的功能之一是count()函数。对于一个新创建的数组我们期望count()函数返回值为0。当我们增加一个元素后,count()应该返回1。Example 1.1中展示了我们想测的东西。
Example 1.1: Testing array operations
<?php
$fixture = array();
// $fixture is expected to be empty.
$fixture[] = 'element';
// $fixture is expected to contain one element.
?>
测试结果是否如我们所想的一个非常简单的方法是,将count()在增加元素之前和之后的结果打印出来。如果分别达到0和1,那么array和count()正如我们所期待的。
Example 1.2: Using print to test array operations
<?php
$fixture = array();
print count($fixture) . "\n";
$fixture[] = 'element';
print count($fixture) . "\n";
?>
0
1
现在,我们将需要手动参与的测试用例进化为自动运行的测试。在Example 1.3中,我们在测试代码中加入了期望值与实际值的比较。如果二者相等,将打印ok, 否则输出not ok, 这样一来,我们就知道某些地方出问题了。
Example 1.3: Comparing expected and actual values to test array operations
<?php
$fixture = array();
print count($fixture) == 0 ? "ok\n" : "not ok\n";
$fixture[] = 'element';
print count($fixture) == 1 ? "ok\n" : "not ok\n";
?>
ok
ok
下一步,我们将期望值与实际值的比较提取出来,放在一个函数中,当二者不一致时,抛出异常。如此一来有两个好处:写测试用例变得更简单,并且只有在出错时才会有输出。
Example 1.4: Using an assertion function to test array operations
<?php
$fixture = array();
assertTrue(count($fixture) == 0);
$fixture[] = 'element';
assertTrue(count($fixture) == 1);
function assertTrue($condition)
{
if (!$condition) {
throw new Exception('Assertion failed.');
}
}
?>
这个测试现在完全自动化了。对比第一个版本,我们仅仅进行了测试,这个版本我们有了一个自动测试。
使用自动测试的目标是制造更少的错误。虽然有了精彩的测试之后,你的代码仍然不完美,但是你将会发现自从使用自动测试后,缺陷激动人心的减少。自动测试会让你对代码有理性的自信。有了这自信,你可以更大胆的修改设计(重构),与你的组员相处的更好(跨组测试),改善与客户的关系,在每天晚上回家之前有了证据证明系统比早上时更好了,因为有了你的努力。