Blog
使用单元测试工具
发布时间: 2009-01-13 10:46
敏捷开发思想
首先,编写类定义;
其次,编写测试用例;
第三,实现类;
第四,实现测试用例;
第五,反复测试修改。
[separator]
准备工作
安装PHPUnit
自动安装
pear install phpunit
手动安装
下载http://pear.phpunit.de/get/PHPUnit-3.3.9.tgz,解压到PHP目录,
将pear-phpunit和pear-phpunit.bat,复制到PHP目录,重命名为phpunit和phpunit.bat,将PHP目录加入PATH路径。
编辑phpunit,修改为:
- #! php -d safe_mode=Off
- set_include_path(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'PHPUnit-3.3.9' . PATH_SEPARATOR . get_include_path());
- require_once 'PHPUnit/Util/Filter.php';
- PHPUnit_Util_Filter::addFileToFilter(__FILE__, 'PHPUNIT');
- require 'PHPUnit/TextUI/Command.php';
- ?>
编辑phpunit.bat,假设PHP路径为D:\PHP,修改为:
@echo off
php -d safe_mode=Off D:\PHP\phpunit %*
现在在终端运行phpunit,看看命令参数。

单元测试实践
编写类定义
- /**
- * 计算器类
- */
- class Calculator
- {
- /**
- * 加法运算
- *
- * @access public
- */
- public function add()
- {
- }
- /**
- * 乘法运算
- *
- * @access public
- */
- public function multiply()
- {
- }
- }
- ?>
编写测试用例
- require_once 'Calculator.php';
- /**
- * 计算器测试用例
- */
- class CalculatorTest extends PHPUnit_Framework_TestCase
- {
- /**
- * @var object
- * @access protected
- */
- protected $object;
- /**
- * 建立测试,在测试方法执行前被调用
- *
- * @access protected
- */
- protected function setUp()
- {
- $this->object = new Calculator();
- }
- /**
- * 拆除测试,在测试方法执行后被调用
- *
- * @access protected
- */
- protected function tearDown()
- {
- }
- /**
- * 测试加法运算
- *
- * @access public
- */
- public function testadd()
- {
- }
- /**
- * 测试乘法运算
- *
- * @access public
- */
- public function testmultiply()
- {
- }
- }
- ?>
实现类
- /**
- * 计算器类
- */
- class Calculator
- {
- /**
- * 加法运算
- *
- * @param int $a
- * @param int $b
- * @access public
- */
- public function add($a, $b)
- {
- return $a + $b;
- }
- /**
- * 乘法运算
- *
- * @param int $a
- * @param int $b
- * @access public
- */
- public function multiply($a, $b)
- {
- return $a * $b;
- }
- }
- ?>
实现测试用例
- require_once 'Calculator.php';
- /**
- * 计算器测试用例
- */
- class CalculatorTest extends PHPUnit_Framework_TestCase
- {
- /**
- * @var object
- * @access protected
- */
- protected $object;
- /**
- * 建立测试,在测试方法执行前被调用
- *
- * @access protected
- */
- protected function setUp()
- {
- $this->object = new Calculator();
- }
- /**
- * 拆除测试,在测试方法执行后被调用
- *
- * @access protected
- */
- protected function tearDown()
- {
- }
- /**
- * 测试加法运算
- *
- * @access public
- */
- public function testadd()
- {
- $expected = 2;
- $result = $this->object->add(1, 1);
- $this->assertEquals($expected, $result);
- }
- /**
- * 测试乘法运算
- *
- * @access public
- */
- public function testmultiply()
- {
- $expected = 4;
- $result = $this->object->multiply(2, 2);
- $this->assertEquals($expected, $result);
- }
- }
- ?>
执行测试
phpunit CalculatorTest.php

进阶
一些方法和属性被声明为保护类型,我们在测试无返回值或被保护的方法时,继承就能解决问题。为什么要测试被保护方法?我个人认为由于PHP是一种语法宽松的语言,因而必须进行更严格的测试,要从最底层确保方法的正确性。如果必要的话,也可以测试私有方法。
- /**
- * 计算器类
- */
- class Calculator
- {
- /**
- * 加法运算
- *
- * @param int $a
- * @param int $b
- * @access protected
- */
- protected function add($a, $b)
- {
- return $a + $b;
- }
- /**
- * 乘法运算
- *
- * @param int $a
- * @param int $b
- * @access protected
- */
- protected function multiply($a, $b)
- {
- return $a * $b;
- }
- }
- ?>
使用继承来测试被保护方法。
- require_once 'Calculator.php';
- class MyCalculator extends Calculator
- {
- }
- /**
- * 计算器测试用例
- */
- class CalculatorTest extends PHPUnit_Framework_TestCase
- {
- /**
- * @var object
- * @access protected
- */
- protected $object;
- /**
- * 建立测试,在测试方法执行前被调用
- *
- * @access protected
- */
- protected function setUp()
- {
- $this->object = new MyCalculator();
- }
- /**
- * 拆除测试,在测试方法执行后被调用
- *
- * @access protected
- */
- protected function tearDown()
- {
- }
- /**
- * 测试加法运算
- *
- * @access public
- */
- public function testadd()
- {
- $expected = 2;
- $result = $this->object->add(1, 1);
- $this->assertEquals($expected, $result);
- }
- /**
- * 测试乘法运算
- *
- * @access public
- */
- public function testmultiply()
- {
- $expected = 4;
- $result = $this->object->multiply(2, 2);
- $this->assertEquals($expected, $result);
- }
- }
- ?>
编写总测试套件
- <?
- // 设置错误报告为严格等级
- error_reporting(E_ALL | E_STRICT);
- // 测试配置文件
- require 'Configure.php';
- // Require PHPUnit
- require_once 'PHPUnit/Util/Filter.php';
- PHPUnit_Util_Filter::addFileToFilter(__FILE__);
- require_once 'PHPUnit/Framework/TestSuite.php';
- require_once 'PHPUnit/Extensions/PhptTestSuite.php';
- // Require test suites
- require_once 'Math/AllTests.php';
- class AllTests
- {
- public static function suite()
- {
- $suite = new PHPUnit_Framework_TestSuite('MyProject');
- $suite->addTest(Math_AllTests::suite());
- return $suite;
- }
- }
- ?>
编写支测试套件 注意:测试用例这里采用目录名加下划线再加原来的测试用例名,来避免不同目录的同名类冲突问题。 目录结构 执行所有测试 备注:phpunit命令可以直接使用不带.php的名称或目录,例如, 自动化测试 自动生成测试用例 该命令会生成一个CalculatorTest.php的测试用例,里面有两个未完成的测试方法testAdd()和testMultiply(),你需要完善它。 持续集成 如果你需要与其他项目集成或集成到IDE工具中,使用ant构建是个不错的注意。 Windows下请将其中的两处 executable="phpunit" 改为 executable="phpunit.bat"。 最佳实践 每次编写好类定义后,自动生成测试用例。实现类和测试用例。修改,执行测试,反复重复这个过程。每次修改后,马上修改测试用例,以免之后忘记。
Lib
+- Math
+- Calculator.php
Tests
+- Math
+- AllTests.php
+- CalculatorTest.php
|- AllTests.php
|- Configure.php
phpunit --verbose AllTests.php
phpunit CalculatorTest
phpunit Math
但是这里建议您在每个目录下都写一个测试套件AllTests.php文件,这么做可以为后期测试节省许多时间。因为如果你的项目中有几十个甚至上百个文件或者目录结构很深,将导致PHP脚本超出内存的错误,而且phpunit每次都需要花很长的时间来生成测试套件。
phpunit --skeleton Calculator.php
编写ant构建文件,让构建、测试、报告、清理一部到位。你可以将下面内容加入你的build.xml文件中。
使用以下命令执行任务:
ant test 执行测试
ant report 生成测试报告
ant clean 清理测试目录
