View
1.565
Download
11
Category
Preview:
Citation preview
PHPUnit入门
PHP User Group Shanghai 2008-04-26
Zhou XianhuaBaohuaCai
PHP User Group Shanghai 2008
1
测试?
• 测试方法– 黑盒测试– 白盒测试
• 测试过程– 单元测试– 集成测试– 压力测试– 并发测试– 环境测试
PHP User Group Shanghai 2008
2
为什么要进行单元测试?
• 保证代码按照特定的行为运行• 减少 Bug• 提高整体项目开发效率• 便于项目后续的维护
PHP User Group Shanghai 2008
3
常见的测试工具• PHP
– PHPUnit、 SimpleTest• ActionScript
– AsUnit• Javascript
– JsUnit、 scriptaculous(unittest)、 crosscheck
• Java– Junit、 TestNG
• Python– PyUnit
PHP User Group Shanghai 2008
4
PHPUnit的特性• 安装、使用方便,是 xUnit家族中的一员• 完全支持 PHP5• 开源、免费、有详细的文档供参考及官方支持• 提供多种格式的测试输出( XML、 JSON、 TAP...)
• 可以自动生成测试类( --skeleton)及从测试类生成应用类
• 提供 Selenium RC 接口,便于在真实的浏览器中测试,实现基于WEB的功能测试。
• 参考: http://www.phpunit.de/wiki/Features
PHP User Group Shanghai 2008
5
安装 PHPUnit
• 使用 PEAR安装– pear channel-discover pear.phpunit.de– pear install phpunit/PHPUnit
• 直接下载压缩包(或从 svn库导出)– http://pear.phpunit.de/get/PHPUnit-3.2.18.tgz– 在 php.ini中设置 include_path,包含 PHPUnit路径
– 把 pear-phpunit改名为 phpunit,并加上可执行属性,把文件中的@php_bin@改成 php可执行命令所在的路径(注:Win下是 pear-phpunit.bat)
– 修改 PHPUnit/Util/Fileloader.php,把文件中的@php_bin@改成 php可执行命令所在的路径
PHP User Group Shanghai 2008
6
安装成功
运行 phpunit– PHPUnit 3.2.18 by Sebastian Bergmann.– Usage: phpunit [switches] UnitTest
[UnitTest.php]– --log-json Log test execution in JSON
format.– --log-tapLog test execution in TAP format
to file.– --log-xml Logtest execution in XML
PHP User Group Shanghai 2008
7
传统的测试// 测试输入的用户名是否合法function checkName($name){ return (bool)preg_match('/^[\w_\d]{3,30}$/',
$name);}// 传统的测试方法echo checkName(”testUserName”) ? ”Y” : ”N”;var_dump(checkName(” ”));if(checkName(”......”)) echo ”...”;
第一个 PHPUnit测试// CheckNameTest.phprequire_once 'PHPUnit/Framework.php';require_once 'checkName.php';
class CheckNameTest extends PHPUnit_Framework_TestCase{ public function testValidateUser() { $this->assertTrue(checkName(”testUser001”)); $this->assertFalse(checkName(”User 001”)); }}
运行第一个 PHPUnit测试
$phpunit CheckNameTest.php
PHPUnit 3.2.18 by Sebastian Bergmann.
Time: 0 seconds
OK (1 test)
测试步骤1. 将类 Class的测试写入 ClassTest2. ClassTest继承(通常)自
PHPUnit_Framework_TestCase3. 测试都是公用方法,命名为 test*4. 在测试方法中,类似 assertEquals()的断言方法用来断言一个实际值(应该)匹配一个期望值
数据提供者class DataTest extends PHPUnit_Framework_TestCase{
public static function provider() { return array(
array(1, 0, 1),array(1, 1, 3)
); }
/* @dataProvider provider */ public function testAdd($a, $b, $c) {
$this->assertEquals($c, $a + $b); }
}
含有通过和失败的测试require_once 'PHPUnit/Framework.php';class MyTest extends
PHPUnit_Framework_TestCase { public function testSuccess() { $this->assertEquals(3, 1 + 2); }
public function testFailure() { $this->assertTrue(2 > 3); }}
含有通过和失败的测试结果
.FTime: 0 seconds
There was 1 failure:
1) testFailure(MyTest)Failed asserting that <boolean:false> is true./home/zhouxh/php/phpunit/MyTest.php:11
FAILURES!Tests: 2, Failures: 1
不同的测试结果. 测试成功输出F 测试当中断言失败时输出E 测试有错误发生时输出S 测试被跳过时输出I 测试未完成时输出
有错误发生的测试( E)public function testError() {
$this->assertLessThan(3);$this->assertEquals(”E?”);
}---------E1) testFailure(MyTest)Missing argument 2 for
PHPUnit_Framework_Assert::assertLessThan(), called in ... ...
被跳过的测试( S)public function testSkip() { $this->markTestSkipped("Skipped test!"); // stop!!! $this->assertTrue(true);}---$phpunit –verbose MyTest.phpS...1) testSkip(MyTest)Skipped test!...
未完成的测试( I)public function testIncomplete() { $this->markTestIncomplete("Incomplete test!"); // stop!!! $this->assertTrue(true);}---$phpunit –verbose MyTest.phpI...1) testIncomplete(MyTest)Incomplete test!...
夹具 (Fixtures)class MyTest extends PHPUnit_Framework_TestCase { public function setUp() { $this->mysqlConnection = mysql_connection(”localhost”,
”root”, ”password”); $this->data = array(1, 2, 3, 4); }
public function testOne() {} public function testTwo() {}
public function tearDown() { mysql_close($this->mysqlConnection); unset($this->data); }}
夹具 (Fixtures)
setUp()testOne()
tearDown()
setUp()testTwo()
tearDown()
同时测试多个文件// AllTests.phprequire_once 'PHPUnit/Framework.php';require_once 'PHPUnit/TextUI/TestRunner.php';
$suite = new PHPUnit_Framework_TestSuite();$suite->addTestFile('tests/CheckNameTest.php');$suite->addTestFile('tests/CheckPasswordTest.php');
PHPUnit_TextUI_TestRunner::run($suite);---$php AllTests.php...
同时测试多个文件// AllTests.phprequire_once 'PHPUnit/Framework.php';require_once 'PHPUnit/TextUI/TestRunner.php';
require_once 'tests/CheckNameTest.php';require_once 'tests/CheckPasswordTest.php';
$suite = new PHPUnit_Framework_TestSuite();$suite->addTestSuite('CheckNameTest');$suite->addTestSuite('CheckPasswordTest');
PHPUnit_TextUI_TestRunner::run($suite);
输出测试require "PHPUnit/Extensions/OutputTestCase.php";
class OutputTest extends PHPUnit_Extensions_OutputTestCase {
public function testOne() { $this->expectOutputString("php"); echo "php"; } public function testTwo() { $this->expectOutputString("phd"); echo "php"; }}
输出测试结果.F
Time: 0 seconds
There was 1 failure:
1) testTwo(OutputTest)Failed asserting that two strings are equal.expected string <phd>difference < x>got string <php>
Tests: 2, Failures: 1.
性能测试require_once 'PHPUnit/Extensions/PerformanceTestCase.php'; class PerformanceTest extends PHPUnit_Extensions_PerformanceTestCase{ public function testPerformance() { $this->setMaxRunningTime(2); sleep(1); }}
其它扩展测试
• 数据库测试– PHPUnit_Extensions_Database_TestCase
• PHP格式测试– PHPUnit_Extensions_PhptTestCase– http://qa.php.net/write-test.php
• Selenium Rc测试– PHPUnit_Extensions_SeleniumTestCase– http://selenium.openqa.org/
测试驱动开发 (TDD)
• 主要开发步骤– 1.编写测试用例– 2.运行测试用例(此时测试结果必然是失败的)– 3.为测试用例编写代码– 4.再次运行测试用例(测试结果是成功或失败的)若失败则返回第 3步继续。
– 5.根据需要清除 /优化相关代码(重构),收工 !
Test Code Test Code
测试驱动开发 (TDD):例子require_once 'PHPUnit/Framework.php';require_once 'Cal.php';class MyTest extends PHPUnit_Framework_TestCase { protected $cal; protected function setUp() { $this->cal = new Cal(); } public function testAdd() { $this->assertEquals(3, $this->cal->add(1, 2)); } public function tearDown() { $this->cal = null; }}
测试驱动开发 (TDD):例子
$phpunit MyTest.php
Fatal error: require_once(): Failed opening required 'Cal.php' (include_path='.:
... ...
测试驱动开发 (TDD):例子
class Cal { public function add() { }}
测试驱动开发 (TDD):例子phpunit MyTest.php
F
Time: 0 seconds
There was 1 failure:
1) testAdd(MyTest)Failed asserting that <null> matches expected value
<integer:3>.
测试驱动开发 (TDD):例子
class Cal { public function add($a, $b) { return $a + $b; }}
测试驱动开发 (TDD):例子
$phpunit MyTest.phpPHPUnit 3.2.18 by Sebastian Bergmann.
.
Time: 0 seconds
OK (1 test)
测试范围分析• 查看代码有哪些被测试了,有哪些没有被测试,用不同的颜色区分开
• 需要 xdebug扩展支持• 输出结果: html、 xml
– phpunit --coverage-html ./reports MyTest.php– phpunit --coverage-xml report.xml MyTest.php
• 覆盖级别:类、方法、行• 支持元标签:
@covers、@codeCoverageIgnoreStart和@codeCoverageIgnoreEnd
测试范围分析$phpunit –coverage-html ./reports MyTest.php
更多 ... ...• 官方网站:• http://www.phpunit.de/• http://planet.phpunit.de/
• 例子(谁在使用 PHPUnit):• http://www.phpunit.de/wiki/WhoUsesPHPUnit• (ZendFramework、 PHP-Gtk2、 Phing... ...)
• 相关工具:• http://www.phpundercontrol.org• http://cruisecontrol.sourceforge.net/• http://www.xdebug.org
Recommended