Php单元测试工具simpletest(一)
 

2009-08-13 来源:网络

 

一、总览

 什么是simpletest?

Simpletest的核心是一套建立在测试用例类上的测试框架。这些测试用例类都是继承自测试用例基类,每个测试用例实际上是测试代码。顶层的测试脚本调用run方法按照顺序执行所有用例类。每个测试方法都调用assert的变种函数来判断测试的结果。

下面是一个测试用例的例子:

<?php

class MyTestCase extends UnitTestCase {

    function testLogWroteMessage() {

        $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/'); 
    } 
}
?>

二、单元测试

单元测试用例

下面是一个测试用例的样例:

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 expectation object $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 dirty debugging

继承测试用例

当然附加的测试方法能被加到创建特殊的测试用例,看下例:

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中。

 运行单个测试用例

一般你很少运行单个测试用例,除非你遇到了一个非常困难的模块。下面是一个运行单个测试用例的例子:

<?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个失败,除非你加了测试方法。


火龙果软件/UML软件工程组织致力于提高您的软件工程实践能力,我们不断地吸取业界的宝贵经验,向您提供经过数百家企业验证的有效的工程技术实践经验,同时关注最新的理论进展,帮助您“领跑您所在行业的软件世界”。
资源网站: UML软件工程组织