Reputation: 2039
I am developing an application with Zend Framework 2. Some of the app services notify interested listeners which trigger some methods in other services, for instance:
UserService
<?php
class UserService implements EventManagerAwareInterface
{
public function create($data = array())
{
// user is already created here
$params = array("user" => $user);
$this->getEventManager()->trigger(__FUNCTION__ . '.post', $this, $params);
}
}
UserListener
<?php
use Zend\EventManager\EventManagerInterface;
use Zend\EventManager\ListenerAggregateInterface;
use Zend\EventManager\EventInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class UserListener implements ListenerAggregateInterface
{
protected $serviceManager;
protected $listeners = array();
public function __construct(ServiceLocatorInterface $serviceManager)
{
$this->serviceManager = $serviceManager;
}
public function attach(EventManagerInterface $events)
{
$evm = $events->getSharedManager();
$this->listeners[] = $evm->attach('Application\Service\UserService', 'create.post', array($this, 'notify'));
}
public function detach(EventManagerInterface $events)
{
foreach ($this->listeners as $index => $listener) {
if ($events->detach($listener)) {
unset($this->listeners[$index]);
}
}
}
public function notify(EventInterface $events)
{
$user = $events->getParam('user');
$mailService = $this->serviceManager->get('MailService');
$mailService->sendWelcomeMessage($user);
}
}
So, my question is what is the best practice to test Zend Framework event listeners with PHPUnit, how all listener methods attach(), detach(), notify() and so on should be properly tested?
Any help would be much appreciated! Thanks in advance!
Upvotes: 2
Views: 1115
Reputation: 129
Here are some helpful hints for attach() and detach(). First the Listener methods to be tested as an example:
/**
* {@inheritdoc}
*/
public function attach(EventManagerInterface $events)
{
$this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH,
[$this, 'doAction']);
}
/**
* {@inheritdoc}
*/
public function detach(EventManagerInterface $events)
{
foreach ($this->listeners as $index => $listener) {
if ($events->detach($listener)) {
unset($this->listeners[$index]);
}
}
}
public function doAction($event)
{
// Code truncated.
}
And the unit test helps, the listener instantiation referred to as $this->listener:
/**
* @covers Application\Event\MyListenerClass::attach
*/
public function testAttach()
{
$eventManager = new EventManager();
$this->listener->attach($eventManager);
$events = $eventManager->getEvents();
// Only one event attached to.
$priorityQueue = $eventManager->getListeners($events[0]);
$callBackHandler = $priorityQueue->extract();
$callBackArray = $callBackHandler->getCallback();
$this->assertEquals($this->listener, $callBackArray[0]);
$this->assertEquals('doAction', $callBackArray[1]);
}
/**
* @covers Application\Event\MyListenerClass::detach
*/
public function testDetach()
{
$eventManager = new EventManager();
$this->listener->attach($eventManager);
$this->listener->detach($eventManager);
$events = $eventManager->getEvents();
// Only one event attached to.
$priorityQueue = $eventManager->getListeners($events[0]);
$this->assertEmpty($priorityQueue->toArray());
}
Finally, it is also possible to use the EventManager from the application's ServiceManager instead of the example instantiation in code here, but this is enough to get someone started.
Upvotes: 0
Reputation: 601
If you look at the apigility zf-mvc-auth source, you'll see lots of examples of listener tests.
https://github.com/zfcampus/zf-mvc-auth/tree/master/test/Authorization
While some could make the claim these aren't totally true unit tests, and they kind of walk a blurred line between unit and functional test, I've found testing listeners in this manner to be the easiest and most effective way to do it without getting into an overmocked testing mess. They're clean, easy to write, and clear to understand.
Upvotes: 3