@
nonesuccess 一般来说,如果待测试的代码使用到了第三方的 api ,应该尽可能地避免在代码里直接依赖,尽量使用依赖注入,然后测试的时候注入一个 mock 的依赖对象,就可以很简单地进行测试了,比如有这样的代码:
class Sample {
function sampleMethod() {
$client = new ThirdpartyClient();
$client->doSomething();
...
}
}
这种代码就非常难以测试,因为你的测试结果会依赖于这个真实的 ThirdpartyClient ,而它的行为是不可控制的,这个时候最好重构一下代码,将 ThirdpartyClient 作为方法的参数(更好的方式是作为这个类的构造方法的参数,然后用依赖注入容器去处理依赖的注入):
class Sample {
function sampleMethod(ThirdpartyClient $client) {
$client->doSomething();
...
}
}
这样,在写测试的时候,就可以注入一个模拟 ThirdpartyClient 行为的 Mock 对象( PHPUnit 的 getMockBuilder 方法可以很方便地进行这个工作),来进行测试工作。
你需要记住的就是单元测试的对象是当前这个代码单元的逻辑, ThirdpartyClient 的行为不在这个测试的范畴内,你只需要假设它始终会按照它的接口说明进行返回就可以了
对于数据库测试,我目前采用的方式是 PHPUnit 的 PHPUnit_Extensions_Database_TestCase 工具来做的
构造一个 fake DAO (这个 DAO 连接的是我的测试数据库),每个模块的测试会单独提供测试数据集, PHPUnit 在执行每个测试用例前,会调用 setUp 方法,这个方法会将测试数据集初始化到测试数据库,然后将这个测试 Dao 注入到待测试的模块,这个模块之后的所有数据库操作,都会通过这个测试 Dao 来执行,就保证了每次执行测试,数据的一致。
这里也有个简单的例子:
class OrderServiceTest extends GenericDatabaseTestCase
{
/**
* 订单模块实例
*
* @
var OrderService
*/
protected $service;
/**
* 初始化测试数据集
*
* @
return \PHPUnit_Extensions_Database_DataSet_CompositeDataSet
* @
throws \Exception
*/
public function getDataSet()
{
return $this->loadTestDataset(
[
'Order/orders',
'Order/order_items',
]
);
}
/**
* 初始化基境
*
* @
return void
* @
throws \Exception
*/
public function setUp()
{
parent::setUp();
$this->service->setDao($this->getMockDao());
}