安装
可以通过pear安装:
$pear channel-discover pear.phpunit.de
$pear channel-discover pear.symfony-project.com
$pear install phpunit
可以下载包:
wget https://phar.phpunit.de/phpunit.phar
chmod +x phpunit.phar
mv phpunit.phar /usr/local/bin/phpunit
先看一个例子:
require_once('UserStore.php');
require_once('PHPUnit/Framework/TestCase.php');
class UserStoreTest extends PHPUnit_Framework_TestCase {
private $store;
public function setUp() {
$this->store = new UserStore();
}
public function testAddUser_ShortPass() {
$this->setExpectedException('Exception');
$this->store->addUser( "bob williams", "a@b.com", "ff" );
$this->fail("Short password exception expected");
}
public function testGetUser() {
$this->store->addUser( "bob williams", "a@b.com", "12345" );
$user = $this->store->getUser( "a@b.com" );
$this->assertEquals( $user['mail'], "a@b.com" );
$this->assertEquals( $user['name'], "bob williams" );
$this->assertEquals( $user['pass'], "12345" );
}
public function tearDown() {}
}
setUp()方法会在每一个测试方法前自动调用.可以设立一个测试环境.
tearDown()方法会在每个测试方法运行后被调用.
测试方法名必须是"test"开头的,或者 加了@test修饰符
断言方法
断言是判断系统中某个假设是否成立的语句或者方法,上例中assertEquals()就是一个断言方法. 除此之外还有:
assertArrayHasKey()
assertClassHasAttribute()
assertClassHasStaticAttribute()
assertContains()
assertContainsOnly()
assertContainsOnlyInstancesOf()
assertCount()
assertEmpty()
assertEqualXMLStructure()
assertEquals()
assertFalse()
assertFileEquals()
assertFileExists()
....
具体可以参考手册.
测试异常
上例中的$this->setExpectedException('Exception'); 指定了期望抛出的异常类型. 这个方法是PHPUnit_Extensions_ExceptionTestCase的方法, 他是phpunit的扩展类.
运行测试套件
把写好的测试类放到一个目录下然后
$phpunit test/
约束
public function testAddUser_duplicate() {
try {
$ret = $this->store->addUser( "bob williams", "a@b.com", "123456" );
$ret = $this->store->addUser( "bob stevens", "a@b.com", "123456" );
self::fail( "Exception should have been thrown" );
} catch ( Exception $e ) {
$const = $this->logicalAnd(
//$this->logicalNot( $this->contains("bob stevens")),
$this->isType('object')
);
self::AssertThat( $this->store->getUser( "a@b.com"), $const );
}
}
约束的实现用断言也可以实现, 约束的有点是逻辑清晰, 而且可以复用.
常用的约束方法:
PHPUnit_Framework_Constraint_Attribute attribute(PHPUnit_Framework_Constraint $constraint, $attributeName)
PHPUnit_Framework_Constraint_IsAnything anything()
PHPUnit_Framework_Constraint_ArrayHasKey arrayHasKey(mixed $key)
PHPUnit_Framework_Constraint_TraversableContains contains(mixed $value)
......
模拟与桩
所谓桩就是stub, 可以理解为占位的伪造的假对象, 它可以使你关注要测试的类本身,而不是整个系统, 免受外部环境影响.
stub对象只是占位, 而mock对象还关注于对行为的预期.
public function testValidate_FalsePass() {
$store = $this->getMock("UserStore");
$this->validator = new Validator( $store );
$store->expects($this->once() )
->method('notifyPasswordFailure')
->with( $this->equalTo('bob@example.com') );
$store->expects( $this->any() )
->method("getUser")
->will( $this->returnValue(new User( "bob williams", "bob@example.com", "right")));
$this->validator->validateUser("bob@example.com", "wrong");
/*
$store = $this->getMock("UserStore");
$store->expects( $this->once() )
->method('notifyPasswordFailure');
//$store->expects( $this->at( 1 ) ) // raise bug
$store->expects( $this->once( ) )
->method("getUser")
->with( $this->equalTo('henry') );
*/
//$store->getUser("bob@bob.com");
}