Symfony 单元测试自定义事件监听器
Symfony Unit test Custom Event Listener
我有自己的事件监听器:
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
客栈命令来构造它。所以:
- 是否建议模拟 HttpKernelInterface?它会破坏 class 的使用吗?
- 是否有更好的方法对
MyExceptionListener
进行单元测试?
您测试的方法将 GetResponseForExceptionEvent
作为参数。这是应该嘲笑的class。
如果您正在测试 GetResponseForExceptionEvent
class(已由 Symfony 开发人员测试),HttpKernelInterface
的模拟是可以接受的。
单元测试不会测试另一个 class 内部发生的事情,只是您测试的 class 完成它的工作并调用其他 class 所需的方法。这意味着测试 MyExceptionListener
实际上是在断言 GetResponseForExceptionEvent
的方法 setResponse
是用正确的参数调用的。
我有自己的事件监听器:
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
客栈命令来构造它。所以:
- 是否建议模拟 HttpKernelInterface?它会破坏 class 的使用吗?
- 是否有更好的方法对
MyExceptionListener
进行单元测试?
您测试的方法将 GetResponseForExceptionEvent
作为参数。这是应该嘲笑的class。
如果您正在测试 GetResponseForExceptionEvent
class(已由 Symfony 开发人员测试),HttpKernelInterface
的模拟是可以接受的。
单元测试不会测试另一个 class 内部发生的事情,只是您测试的 class 完成它的工作并调用其他 class 所需的方法。这意味着测试 MyExceptionListener
实际上是在断言 GetResponseForExceptionEvent
的方法 setResponse
是用正确的参数调用的。