我有一个类来处理各种数据库异常,例如死锁和序列化事务失败。我正试图对它进行单元测试并遇到障碍。我要测试的代码示例:
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');
});
A non well formed numeric value encountered
。 PDOException
与Exception
中断合同,因为异常代码必须为int,PDOException
创建字符串代码以匹配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;
}
}
这不会编译因为'无法覆盖最终方法Exception-> getCode()'。
由于我不能(并且不想)使用真实数据库重新创建每种类型的死锁和事务错误,如何编写单元测试哪些需要抛出PDOException
?< /强>
答案 0 :(得分:1)
您不需要覆盖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;});
回应&#39;预期&#39;;