Php 如何编写引发异常的单元测试
我有一个类,它处理各种数据库异常,例如死锁和序列化事务失败。我试图对它进行单元测试,但遇到了一个障碍。我想测试的代码示例如下:Php 如何编写引发异常的单元测试,php,unit-testing,pdo,phpunit,Php,Unit Testing,Pdo,Phpunit,我有一个类,它处理各种数据库异常,例如死锁和序列化事务失败。我试图对它进行单元测试,但遇到了一个障碍。我想测试的代码示例如下: public function run(callable $callable) { $this->beginTransaction(); try { $callable(); $this->commit(); } catch (\PDOException $e) { if ($e->
public function run(callable $callable)
{
$this->beginTransaction();
try {
$callable();
$this->commit();
} catch (\PDOException $e) {
if ($e->getCode() == '40P01' || $e->getCode() == '55P03') {
// Deadlock (40P01) or lock not available (55P03).
...
}
...
}
}
PDOException
的文档说开发人员不应该自己抛出它,今天我发现了为什么在尝试编写单元测试时:
$obj->run(function() {
...
throw new \PDOException('Deadlock', '40P01');
});
遇到格式不正确的数值
pdotexception
使用Exception
打破合同,因为异常代码必须是int,并且pdotexception
创建字符串代码以匹配SQL标准。他们应该创建一个单独的SQLCode属性,但应该重用内置代码。因此,不可能在单元测试中抛出带有真实SQL错误代码的PDOException
接下来,我尝试模拟PDOException
:
class PDOExceptionMock extends \PDOException
{
protected $code = '';
public function setCode($code)
{
$this->code = $code;
}
// This won't work because getCode is final
public function getCode()
{
return $this->code;
}
}
这不会编译,因为“无法覆盖最终方法异常->getCode()”
既然我不能(也不想)使用真实的数据库重新创建每种类型的死锁和事务错误,如何编写需要抛出
PDOException
s的单元测试?您不需要覆盖getCode
。它已经存在,所以您只需要设置代码。例如
class A {
public function run(callable $callable)
{
try {
$callable();
} catch (\PDOException $e) {
if ($e->getCode() == '40P01' || $e->getCode() == '55P03') {
return 'expected';
}
return 'unexpected';
}
return 'no caught';
}
}
class StubException extends \PDOException {
public function __construct() {
parent::__construct();
$this->code = '40P01';
}
}
$a = new A;
echo $a->run(function(){throw new StubException;});
“预期”的回声 吹毛求疵:仅仅因为自动化测试是使用PHPUnit实现的,并不意味着它是一个单元测试。运行与数据库对话的代码的测试不是单元测试。@SebastianBergmann,他不想接触数据库,而是测试处理死锁的逻辑。啊,没有注意到我们可以直接访问内部
code
属性。太明显了!对我有用。谢谢