PHPUnit:模拟PDOException-> getMessage()方法

时间:2016-03-01 13:33:55

标签: php exception mocking phpunit

我正在编写一个基本的PDO包装器类,当我想在我的单元测试中使用PDOStatement::prepare()模拟willThrowException()模拟PDOException抛出异常时,返回getMessage()的值总是空字符串而不是我设置的字符串。

以下是我尝试的方法:

// WrapperClass.php
<?php 

class WrapperClass
{

    private $pdo;
    private $error = '';

    public function __construct(\PDO $pdo)
    {
        $this->pdo = $pdo;
    }

    public function save()
    {
        $sql = 'INSERT INTO ...';

        try {
            $this->pdo->prepare($sql);

            // some value binding and executing the statement
        } catch (\PDOException $pdoException) {
            $this->error = $pdoException->getMessage();
        }
    }

    public function getError()
    {
        return $this->error;
    }
}

和我的测试:

// WrapperClassTest.php
<?php 

class WrapperClassTest extends \PHPUnit_Framework_TestCase
{

    /**
     * @test
     */
    public function save_saves_PDOException_message_in_error_property()
    {
        $pdoMock = $this->getMockBuilder('WrapperClass')
                        ->disableOriginalConstructor()
                        ->setMethods(['prepare'])
                        ->getMock();
        $pdoMock->expects($this->once())
                ->method('prepare')
                ->willThrowException($pdoExceptionMock);
        $pdoExceptionMock = $this->getMockBuilder('\PDOException')
                        ->setMethods(['getMessage'])
                        ->getMock();
        $message = 'Message from PDOException';
        $pdoExceptionMock->expects($this->once())
                ->method('getMessage')
                ->willReturn($message);

        $wrapperClass = new WrapperClass($pdoMock);
        $wrapperClass->save();

        $this->assertEquals($message, $wrapperClass->getError());
    }
}

我还尝试将->willThrowException($pdoException)替换为->will($this->throwException($pdoException)),但它不起作用。

我注意到,如果我将->willThrowException($pdoException)替换为->willThrowException(new \PDOException('Message from PDOException')),那么它可以正常工作,但我依靠PDOException类而不是嘲笑它。

有什么想法吗?

1 个答案:

答案 0 :(得分:3)

只有2个陈述:

1)PHP 5.x中的所有异常都扩展了基本异常和it defines&#39; getMessage&#39;最后的方法:

final public string Exception::getMessage ( void )

2)当您尝试模拟最终方法时,PHPUnit会默默地执行任何操作(您可以看到生成模拟here的代码,canMockMethod为最终方法返回false)

所以

->setMethods(['getMessage'])

没有效果。

另一方面,你并不需要模拟异常,因为它们是价值对象。传递new PDOException('Message from PDOException')非常好。