2016-03-01 5 views
3

Я пишу базовый PDO класс-оболочку, и когда я хочу, чтобы имитировать бросание исключения путем использования PDOStatement::prepare()willThrowException() с издеваться из PDOException в моем тестовом модуле, возвращенное значение getMessage() всегда и пустая строка, а не то, что я создал.PHPUnit: Mocking 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 вместо того, чтобы издеваться над ним.

Любые идеи?

+0

Глупые мысли, но может ли порядок заявлений иметь значение? Вы говорите ему, чтобы он выкинул pdoExceptionMock, но заполнил данные после назначения его вашему pdoMock. –

ответ

2

всего 2 заявления:

1) Все исключения в PHP 5.x расширяет базовый Exception и it defines метод '' GetMessage как окончательный:

final public string Exception::getMessage (void) 

2) PHPUnit молча ничего не делать, когда вы пытаетесь фиктивные конечные методы (вы можете увидеть код, который генерирует издевается here, canMockMethod возвращает ложные для конечных методов)

Так

->setMethods(['getMessage']) 

не оказывает никакого эффекта.

С другой стороны, вам действительно не нужно издеваться над исключениями, потому что они являются объектами ценности. Прохождение new PDOException('Message from PDOException') довольно нормально.

+0

В этом конкретном случае нет проблем не издеваться над исключением. Это становится проблемой, однако, в таких случаях, как Guzzle, где у вас есть несколько параметров. Например RequestException: 'общественная функция __construct ( $ сообщение, RequestInterface $ запрос, ResponseInterface $ ответ = нуль, \ Exception $ предыдущий = нуль, массив $ handlerContext = []' –

Смежные вопросы