2016-05-03 4 views
1

Я использую PHPUnit ~5.2 и PHP ~7.0.0.Использование expectException и шпион в PHPUnit

У меня есть класс, который обертывает репозиторий, улавливает исключения, которые он выбрасывает, вызывает регистратор, а затем повторно вызывает исключение.

public function storeDonation(Donation $donation) { 
    try { 
     $this->repository->storeDonation($donation); 
    } 
    catch (StoreDonationException $ex) { 
     $this->logger->log($this->logLevel, $ex->getMessage(), [ 'exception' => $ex ]); 
     throw $ex; 
    } 
} 

В моих тестах я создал шпион для регистратора, так что я могу видеть, какие вызовы, где производятся с функциями регистрации. Этот шпион - это специальный тестовый двойной NOT, созданный с помощью PHPUnit mocking API. Проблема, с которой я сталкиваюсь, не будет возникать при использовании PHPUnit mocking API, однако я не спрашиваю об отзывах для этого решения здесь.

Метод испытания, где я бегу в проблемы есть код установки, то есть вызов PHPUnits expectException (которые раньше были setExpectedException в PHPUnit 5.1 и старше), а затем вызывает метод производства, и, наконец, получает записывая звонки со шпиона, чтобы утверждать правильные, где они сделаны.

public function testWhenGetDonationByIdThrowException_itIsLoggedAndThrown() { 
    $logger = new LoggerSpy(); 

    $loggingRepo = new LoggingDonationRepository(
     $this->newThrowingRepository(), 
     $logger 
    ); 

    $this->expectException(GetDonationException::class); 
    $loggingRepo->getDonationById(1337); 

    $this->assertEquals(
     [ 
      [ 
       LogLevel::CRITICAL, 
       self::GET_DONATION_BY_ID_EXCEPTION_MESSAGE, 
       $this->newGetDonationException() 
      ] 
     ], 
     $logger->getLogCalls() 
    ); 
} 

Проблема заключается в том, что, когда исключение брошено, PHPUnit ловит его и оценивает expectException, после чего выполнение моего метода испытания не продолжается. Таким образом, утверждения, использующие мой шпион, никогда не запускаются.

Я ищу способ решить эту проблему. Я рассмотрел разделение метода на тот, у которого есть часть expectException, и другая, которая имеет как фиктивный try-catch для вызова производственного кода, так и утверждения для шпиона. Любые предложения более приятных подходов?

ответ

3

Когда вы бросаете исключение, весь следующий код прерывается до выписки. Это также касается вашего тестового метода.

PHPUnit всегда улавливает исключения, поэтому он может их регистрировать, и с помощью expectedException вы просто скажете, чтобы он обрабатывал исключение, которое было немного изменено.

Так что да, вам нужно будет написать свой собственный блок try catch, если вы хотите захотеть выполнить другие проверки после того, как было выбрано исключение. Вот пример того, как вы это сделаете:

public function testWhenGetDonationByIdThrowException_itIsLoggedAndThrown() { 
    $logger = new LoggerSpy(); 

    $loggingRepo = new LoggingDonationRepository(
     $this->newThrowingRepository(), 
     $logger 
    ); 

    try { 
     $loggingRepo->getDonationById(1337); 
    } catch (GetDonationException $e) { 
     $this->assertEquals(
      [[ 
       LogLevel::CRITICAL, 
       self::GET_DONATION_BY_ID_EXCEPTION_MESSAGE, 
       $this->newGetDonationException() 
      ]], 
      $loger->getLogCalls() 
     ); 

     return; 
    } 

    $this->fail('Expected exception wasn\'t thrown!'); 
}