PHPUnit阅读笔记 - 2
安装PHPUnit
合适的版本
PHPUnit 4.x版本支持PHP 5.4/5.5/5.6
PHPUnit 5.x支持PHP 5.6/7.x
PHPUnit 6.x版本仅支持PHP 7.x。
安装
Composer
利用composer包管理器进行安装是目前较为方便的方式。
composer require phpunit/phpunit ~4.8.0 -vvv
Pear
依据官方说明,PHPUnit不在支持使用pear
进行安装。
书写测试代码
测试类应继承PHPUnit_Framework_TestCase
(PHPUnit 4.x/5.x)/PHPUnit\Framework\TestCase
(PHPUnit 6.x);也可以对这个类进行扩展,扩展的方法类似对异常的扩展。
以下为guzzle/guzzle库中的一个测试:
<?php
namespace GuzzleHttp\Tests\Event;
//use ...;
class ConnectExceptionTest extends \PHPUnit_Framework_TestCase
{
public function testHasNoResponse()
{
//...测试代码
}
}
简单的测试
测试类一般按照*Test
的方式命名,*
一般为要测试的类名。
测试方法一般都以test*
的方式命名,*
一般为要测试的类中的方法名;也可以在方法注释中加入@test
注解标记为测试方法。
下列两种书写方法均为测试方法:
<?php
class FooTest extends PHPUnit_Framework_TestCase
{
public function testMethod1()
{
//method1的测试代码
$this->assertEquals(true, false);
}
/**
* test method2
* @test
*/
public function method2()
{
//method2的测试代码
$this->assertEmpty(false);
}
}
测试代码中调用的assert*
方法由PHPUnit_Framework_TestCase
提供,方法描述由简单的英文组成,一般都能看懂。
具体的方法可以参照文档。
有依赖的测试
这种情况指的是:测试方法需要其他测试方法提供的基境(这里可以解释为参数,即待测试的方法需要其他测试方法提供的结果作为参数)。
需要在方法注释中,以@depends methodName
的方式声明需要的基境方法,需要多个基境的按照顺序写下去即可。
例如,method3
需要testMethod1
和method2
的运行结果作为参数:
<?php
namespace Foo;
use PHPUnit_Framework_TestCase;
class FooTest extends PHPUnit_Framework_TestCase
{
public function testMethod1()
{
$this->assertEquals(false, false);
return 0;
}
/**
*
* @test
*/
public function method2()
{
$this->assertTrue(true);
return '';
}
/**
* @test
* @depends testMethod1
* @depends method2
*/
public function method3($a, $b)
{
$this->assertEquals($a, $b);
}
}
有数据供给的测试
这种情况针对的是有较多不同的case,需要不同的测试用例才能测完全的测试。
测试方法中可以传入参数,提供不同参数的方法称为数据提供器方法,在测试中用@dataProvider methodName
来进行标记。
后文用个例子来说明这种情况,以下是手册中关于此部分的示例。
<?php
class DataTest extends PHPUnit_Framework_TestCase
{
/**
* @dataProvider additionProvider
*/
public function testAdd($a, $b, $expected)
{
$this->assertEquals($expected, $a + $b);
}
public function additionProvider()
{
return array(
array(0, 0, 0),
array(0, 1, 1),
array(1, 0, 1),
array(1, 1, 3)
);
}
}
对异常的测试
有以下三种对异常进行测试的方式:
- annonation
<?php
class DataTest extends PHPUnit_Framework_TestCase
{
/**
* @expectedException \Exception
* @expectedExceptionCode 0
* @expectedExceptionMessage hello
* @expectedExceptionMessageRegExp #^he.*#
*/
public function testCatchExceptionAnnotation()
{
throw new \Exception('hello world');
}
}
@expectedExceptionMessage
指定的Message是被抛出异常信息中包含指定的字符,不是完全相同。
- 调用setException系列方法
<?php
class DataTest extends PHPUnit_Framework_TestCase
{
public function testCacheExceptionFunction() {
$this->setExpectedException('\Exception', 'hello', 0);
$this->setExpectedExceptionRegExp('\Exception', '#he.*#', 0);
throw new \Exception('hello world');
}
}
setExpectedException
指定的Message是被抛出异常信息中包含指定的字符,不是完全相同。
- 利用try…catch…特定测试
<?php
class ExceptionTest extends PHPUnit_Framework_TestCase {
public function testException() {
try {
// ... 预期会引发异常的代码 ...
}
catch (InvalidArgumentException $expected) {
return;
}
$this->fail('预期的异常未出现。');
}
}
1、2方法一般只能对一个异常进行测试,3可以对多种多个异常进行测试,视需求而定。
对错误的测试
PHPUnit里面定义了PHP的错误异常类型,基类PHPUnit_Framework_Error
,各种PHP错误类PHPUnit_Framework_Error_Deprecated
,PHPUnit_Framework_Error_Notice
,PHPUnit_Framework_Error_Warning
。
对输出的测试
与对异常测试相类似,可以在测试方法开始设定要测试输出的字符,方法有expectOutputRegex
和expectOutputString
。
与异常测试不同的是,expectOutputString
指定的字符必须与输出字符完全相同方可通过测试。
<?php
namespace App\Foo;
/**
* Generated by PHPUnit_SkeletonGenerator on 2017-02-13 at 11:35:47.
*/
class FooTest extends \PHPUnit_Framework_TestCase
{
public function testEchoStr()
{
$this->expectOutputString("hello");
echo "hello";
}
public function testEchoStrRegex()
{
$this->expectOutputRegex("#^he.*#");
echo "hello";
}
}
跳过测试
未完成测试
开始写新的测试用例类时,可能想从写下空测试方法开始,而PHPUnit会将空测试方法标记为成功,这没有任何意义。
所以,我们需要把空测试方法标记为未完成markTestIncomplete
,类似annoation@todo
。
<?php
namespace App\Foo;
/**
* Generated by PHPUnit_SkeletonGenerator on 2017-02-13 at 11:35:47.
*/
class FooTest extends \PHPUnit_Framework_TestCase
{
public function testUncompleted()
{
$this->markTestIncomplete(
'此测试目前尚未实现。'
);
}
}
环境条件不符合跳过测试
由于不同环境中PHP版本、扩展、依赖等不相同,编写的单元测试可能在不同环境中出现不同测测试结果。
这时我们需要对测试用例进行条件限定,对于PHP版本
,PHP扩展
,操作系统
,函数存在
,可以使用@requires
进行限定。
<?php
namespace App\Foo;
/**
* Generated by PHPUnit_SkeletonGenerator on 2017-02-13 at 11:35:47.
*/
class FooTest extends \PHPUnit_Framework_TestCase
{
/**
* @requires PHP 5.3
* @requires OS Linux
* @requires function mb_substr
* @requires extension redis
*/
public function testSkipped()
{
// some tests
}
}
对于复杂的条件,我们可以在测试代码中自行编写条件,进行跳过判定。
<?php
class DatabaseTest extends PHPUnit_Framework_TestCase
{
protected function setUp()
{
if (!extension_loaded('mysqli')) {
$this->markTestSkipped(
'The MySQLi 扩展不可用。'
);
}
}
public function testConnection()
{
// ...
}
}
?>
小结
以上是书写PHPUnit测试的基本格式。