2017-11-07 3 views
1

私は私自身のイベントリスナーの魔道士を持っている:symfonyのユニットテストカスタムイベントリスナ

namespace AppBundle\EventHandlers; 

use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; 
use Symfony\Component\HttpFoundation\Response; 

class MyExceptionListener 
{ 
    /** 
    * @var string 
    */ 
    private $env; 

    /** 
    * @var null|\Twig_Environment 
    */ 
    private $twig=null; 

    private $forOfourExceptions=[ 
     AppBunble\Exceptions\ApiReturnedNoDataException::class, 
     AppBunble\Exceptions\DatabaseReturnedNoDataException::class, 
     Symfony\Component\HttpKernel\Exception\NotFoundHttpException::class 
    ]; 

    public function __construct($env,\Twig_Environment $twig) 
    { 
     $this->env = $env; 
     $this->twig=$twig; 
    } 

    public function onKernelException(GetResponseForExceptionEvent $event) 
    { 
     // You get the exception object from the received event 
     $exception = $event->getException(); 

     $exceptionClass=get_class($exception); 

     // Customize your response object to display the exception details 
     $response = new Response(); 

     $content=""; 
     if(in_array($exceptionClass,ExceptionMapping::RETURN_ERROR_FOUR_HUNDRED_FOUR)){ 
      $response ->setStatusCode(Response::HTTP_NOT_FOUND); 
      $content = $this->twig->render('error_404.html.twig'); 
     } else { 
      $response ->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR); 

      if($this->env == 'dev'){//Only on production set response 
       return; 
      } 
     } 

     $response->setContent($content); 

     // Send the modified response object to the event 
     $event->setResponse($response); 
    } 
} 

そして私次ユニットテストでした:

namespace AppBundle\Tests\EventHandlers; 

use AppBundle\Exceptions\ApiReturnedNoDataException; 
use PHPUnit\Framework\TestCase; 
use AppBundle\EventHandlers\MyExceptionListener; 
use Symfony\Component\HttpFoundation\Response; 
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; 

class ExceptionListenerTest extends TestCase 
{ 

    public function testnoDataExceptionTest() 
    { 
     /** 
     * @var ExceptionListener 
     */ 
     $class=$this->constructClass(); 

     $exception=new ApiReturnedNoDataException('giberish'); 

     $responseEvent=$this->getMockBuilder(GetResponseForExceptionEvent::class) 
           ->disableOriginalConstructor() 
           ->getMock(); 

     $responseEvent->method('getException')->willReturn($exception); 

     /** 
     * @var Response 
     */ 
     $class->onKernelException($responseEvent); 

     $this->assertEquals($response->getStatusCode(),Response::HTTP_NOT_FOUND); 
    } 

    /** 
    * @return ExceptionListener 
    */ 
    private function constructClass() 
    { 

     $twigMock=$this->getMockBuilder(\Twig_Environment::class) 
          ->disableOriginalConstructor() 
          ->getMock(); 

     $twigMock->method('render')->willReturn(''); 

     $exceptionListener= new ExceptionListener('prod',$twigMock); 

     return $exceptionListener; 
    } 
} 

しかしphpoUnitが正しく例外:

1) AppBundle\Tests\Managers\ExceptionListenerTest::testnoDataExceptionTest 
Error: Call to a member function getStatusCode() on null 

したがって、正しいGetResponseForExceptionEventを構築する必要がありますが、そのコンストラクタはHttpKernelInterface inn ordを渡す必要がありますそれを構築する。したがって:

  • HttpKernelInterfaceをモックすることをお勧めしますか?クラスの使用を壊すのだろうか?
  • ユニットテストには、MyExceptionListenerの方がいいですか?
+0

ここで、テストでは、リスナーを通して送信されたイベントから '$ response'を設定していますか? –

+0

今のところ私はこれを理解しようとしていません。 –

答えて

1

あなたのテスト済みのメソッドは、引数としてGetResponseForExceptionEventが必要です。これは嘲笑すべきクラスです。

GetResponseForExceptionEventクラス(既にSymfony開発者がテスト済み)をテストしていた場合は、HttpKernelInterfaceのMockingを受け入れることができます。

ユニットテストでは、別のクラス内で何が起こるかはテストされません。テストされたクラスはそのジョブを実行し、他のクラスのメソッドが必要です。つまり、MyExceptionListenerのテストでは、のGetResponseForExceptionEventというメソッドが正しい引数で呼び出されていると主張しています。

+0

しかし、嘲笑してもデフォルトの方法はそのままですか? –

+0

あなたは自分で必要なすべての方法を模擬します。アプリケーションを実行しているわけではなく、ユニットテストだけなので、他のものは必要ありません。 – svgrafov

+0

しかし、setResponseを設定する必要があることが分かりますが、どのようにして偽装することができますが、何も返されず、 'GetResponseForExceptionEvent'の働きに影響します。 –