【问题标题】:PHPUnit: Mocking PDOException->getMessage() methodPHPUnit:模拟 PDOException->getMessage() 方法
【发布时间】:2016-06-13 22:57:09
【问题描述】:

我正在编写一个基本的 PDO 包装类,当我想在单元测试中使用 willThrowException() 和 PDOException 的模拟来模拟 PDOStatement::prepare() 抛出异常时,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());
    }
}

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

我注意到,如果我将 -&gt;willThrowException($pdoException) 替换为 -&gt;willThrowException(new \PDOException('Message from PDOException')) 它可以工作,但是我依赖于 PDOException 类而不是模拟它。

有什么想法吗?

【问题讨论】:

  • 愚蠢的想法,但声明的顺序重要吗?您告诉它抛出 pdoExceptionMock,但在将数据分配给您的 pdoMock 后填充数据。

标签: php exception mocking phpunit


【解决方案1】:

只有两条语句:

1) PHP 5.x 中的所有异常都将基本异常和it defines 'getMessage' 方法扩展为 final:

final public string Exception::getMessage ( void )

2) 当你尝试模拟 final 方法时,PHPUnit 默默地什么都不做(你可以看到生成模拟的代码 here,canMockMethod 为 final 方法返回 false)

所以

->setMethods(['getMessage'])

没有效果。

另一方面,您实际上并不需要模拟异常,因为它们是值对象。通过new PDOException('Message from PDOException') 就可以了。

【讨论】:

  • 在这种特定情况下,不模拟异常没有问题。然而,在像 Guzzle 这样您有多个参数的情况下,这会成为一个问题。例如 RequestException:public function __construct( $message, RequestInterface $request, ResponseInterface $response = null, \Exception $previous = null, array $handlerContext = []
  • 我没有意识到它是最终的。感谢您澄清这一点。
猜你喜欢
  • 1970-01-01
  • 2013-01-27
  • 2021-04-27
  • 1970-01-01
  • 2021-06-16
  • 2020-11-15
  • 1970-01-01
  • 1970-01-01
  • 2014-08-24
相关资源
最近更新 更多