Php单元测试工具simpletest
一、总览
l什么是simpletest?
Simpletest的核心是一套建立在测试用例类上的测试框架。这些测试用例类都是继承自测试用例基类,每个测试用例实际上是测试代码。顶层的测试脚本调用run方法按照顺序执行所有用例类。每个测试方法都调用assert的变种函数来判断测试的结果。
下面是一个测试用例的例子:
<?php
class MyTestCase extends UnitTestCase {
functiontestLogWroteMessage() {
$log = &new Log('my.log');
$log->message('Hello');
$this->assertTrue(file_exists('my.log'));
}
}
?>
这些工具是为开发者而写的。测试用php语言写成。用php语言的优势是不用学习新的语言,测试可以马上开始,开发者可以测试任何部分代码。一般所有能被应用程序访问的代码,也能被测试代码访问,如果他们是同一种语言的话。
测试用例最简单的类型是UnitTestCase,这个类包含了所有用于质量、引用、模式匹配的标准测试。这些是绝大多数日常开发的测试所需要的。
Web应用程序的顶级任务不是产生正确的输出,而是生成页面。WebTestCase类用于测试web页面。他仿真了web浏览器对页面的请求,包括cookie、代理、安全连接、验证、表单、frame以及大多数导航元素。有了这个类,开发者能判断页面的信息正确与否。
一个web测试用例的例子:
<?php
class MySiteTest extends WebTestCase {
function testHomePage() {
$this->get('http://www.my-site.com/index.php');
$this->assertTitle('My Home Page');
$this->clickLink('Contact');
$this->assertTitle('Contact me');
$this->assertPattern('/Email me at/');
}
}
?>
二、单元测试
l单元测试用例
下面是一个测试用例的样例:
class FileTestCase extends UnitTestCase {
}
一般的,测试用例中总是有一些方法,这些方法的名称以”test”开头,这些方法会在run中被自动调用,应该根据实际需要尽可能多的增加测试方法。
例如:
require_once('../classes/writer.php');
class FileTestCase extends UnitTestCase {
function FileTestCase() {
$this->UnitTestCase('File test');
}
function setUp() {
@unlink('../temp/test.txt');
}
function tearDown() {
@unlink('../temp/test.txt');
}
function testCreation() {
$writer = &new FileWriter('../temp/test.txt');
$writer->write('Hello');
$this->assertTrue(file_exists('../temp/test.txt'), 'File created');
}
}
构造函数是可选的,通常被省略。
在上面的例子中,我们唯一的方法是testCreation函数,用于测试文件是否被Writer对象创建。我们也能在这个方法中放上unlink函数,但是我们将清理临时文件的任务交给了setUp和tearDown。
setUp运行于每个测试方法运行之前,tearDown运行于每个测试方法运行之后。
我们用assert系列函数来判断运行结果。下面是UnitTestCase类的全部assert函数列表:
assertTrue($x) | Fail if $x is false |
assertFalse($x) | Fail if $x is true |
assertNull($x) | Fail if $x is set |
assertNotNull($x) | Fail if $x not set |
assertIsA($x, $t) | Fail if $x is not the class or type $t |
assertNotA($x, $t) | Fail if $x is of the class or type $t |
assertEqual($x, $y) | Fail if $x == $y is false |
assertNotEqual($x, $y) | Fail if $x == $y is true |
assertWithinMargin($x, $y, $m) | Fail if abs($x - $y) < $m is false |
assertOutsideMargin($x, $y, $m) | Fail if abs($x - $y) < $m is true |
assertIdentical($x, $y) | Fail if $x == $y is false or a type mismatch |
assertNotIdentical($x, $y) | Fail if $x == $y is true and types match |
assertReference($x, $y) | Fail unless $x and $y are the same variable |
assertClone($x, $y) | Fail unless $x and $y are identical copies |
assertPattern($p, $x) | Fail unless the regex $p matches $x |
assertNoPattern($p, $x) | Fail if the regex $p matches $x |
expectError($x) | Swallows any upcoming matching error |
assert($e) | Fail on failed expectationobject $e |
所有的assert函数能加一个可选的描述作为最后一个参数。这能标识结果。如果省略此函数,将显示默认提示。默认提示字符串也能在自定义字符串中用”%s”来引用,所有判断返回true表示通过,返回false表示失败!
下面是一些例子:
$variable = null;
$this->assertNull($variable, 'Should be cleared');
…将通过,并且不显示信息。如果你设置了通过的也要显示的设置器,消息将被显示。
$this->assertIdentical(0, false, 'Zero is not false [%s]');
这个函数将失败,当他执行类型检查时,”%s”将被默认的错误消息替换。
$a = 1;
$b = $a;
$this->assertReference($a, $b);
将失败,因为a是b的副本。
$this->assertPattern('/hello/i', 'Hello world');
将通过,因为用大小写不敏感匹配,hello包含在Hello world中。
单元测试用例也有一些方便的方法用于调试和扩展用例:
setUp() | Runs this before each test method |
tearDown() | Runs this after each test method |
pass() | Sends a test pass |
fail() | Sends a test failure |
error() | Sends an exception event |
signal($type, $payload) | Sends a user defined message to the test reporter |
dump($var) | Does a formatted print_r() for quick and dirtydebugging |
l继承测试用例
当然附加的测试方法能被加到创建特殊的测试用例,看下例:
require_once('simpletest/unit_tester.php');
class FileTester extends UnitTestCase {
function FileTester($name = false) {
$this->UnitTestCase($name);
}
function assertFileExists($filename, $message = '%s') {
$this->assertTrue(
file_exists($filename),
sprintf($message, 'File [$filename] existence check'));
}
}
这儿,SimpleTest库放在本地目录simpletest中,用你的服务器路径代替它。
为了防止这个用例运行,应该明智的将它标记为abstract。
新的用例现在能将它作为单元测试用例基类,继承于它,看下例:
class FileTestCase extends FileTester {
function setUp() {
@unlink('../temp/test.txt');
}
function tearDown() {
@unlink('../temp/test.txt');
}
function testCreation() {
$writer = &new FileWriter('../temp/test.txt');
$writer->write('Hello');
$this->assertFileExists('../temp/test.txt');
}
}
如果你想要的测试用例不需要UnitTestCase的一些assert函数,只有你自己的一些基础函数,那么你需要继承于SimpleTestCase,他在simple_test.php中。
l运行单个测试用例
一般你很少运行单个测试用例,除非你遇到了一个非常困难的模块。下面是一个运行单个测试用例的例子:
<?php
require_once('simpletest/unit_tester.php');
require_once('simpletest/reporter.php');
require_once('../classes/writer.php');
class FileTestCase extends UnitTestCase {
function FileTestCase() {
$this->UnitTestCase('File test');
}
}
$test = &new FileTestCase();
$test->run(new HtmlReporter());
?>
这个用例将运行,运行结果是0个通过,0个失败,除非你加了测试方法。