Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/281.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 如何编写引发异常的单元测试_Php_Unit Testing_Pdo_Phpunit - Fatal编程技术网

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
属性。太明显了!对我有用。谢谢