Robert Basic's blog

Posts tagged 'zend framework 2'

Unit testing Zend Framework 2 modules

by Robert Basic on September 15, 2012.
Heads-up! You're reading an old post and the information in it is quite probably outdated.

Porting this blog to Zend Framework 2, I decided to write some unit tests as well, while I’m at it. Not that the current code base doesn’t have unit tests, just it doesn’t have much of it… Anyway, I’d like to show how to get unit tests for modules up and running, as well how to throw in Mockery in the mix, as it can help us greatly with mocking out objects. Some of the parts shown here probably could be written in a more cleaner/nicer way, especially the autoloading bit, but so far it works for me.

The phpunit.xml file is rather simple:

<phpunit bootstrap='./bootstrap.php' colors='true'>
    <testsuite name='ZF2 Module Test Suite'>
        <directory>.</directory>
    </testsuite>
    <filter>
        <whitelist>
            <directory suffix='.php'>../src/</directory>
        </whitelist>
    </filter>
    <listeners>
        <listener class="\Mockery\Adapter\Phpunit\TestListener"
            file="Mockery/Adapter/Phpunit/TestListener.php"></listener>
    </listeners>
</phpunit>

The Mockery TestListener, as I found out the hard way, is needed for Mockery to work properly. You might add in some more stuff, like generating code coverage reports, and the like.

In the bootstrap.php we set up the autoloading for the modules, the ZF2 library, and Mockery:

<?php
putenv('ZF2_PATH=' . __DIR__ . '/../../../vendor/ZF2/library');
include_once __DIR__ . '/../../../init_autoloader.php';
set_include_path(implode(PATH_SEPARATOR, array(
    '.',
    __DIR__ . '/../src',
    __DIR__ . '/../../SomeRequiredModule/src',
    __DIR__ . '/../../../vendor',
    get_include_path(),
)));
spl_autoload_register(function($class) {
    $file = str_replace(array('\\', '_'), DIRECTORY_SEPARATOR, $class) . '.php';
    if (false === ($realpath = stream_resolve_include_path($file))) {
        return false;
    }
    include_once $realpath;
});
$loader = new \Mockery\Loader;
$loader->register();

It assumes that the currently tested module lives inside a ZF2 application. If not, you’ll probably need to adjust the paths accordingly. It also assumes that the Mockery files are in the vendor/ directory.

Testing the service layer

Don’t want to get into a fight about terminology, but the service layer for me, is the layer that lives between the controller layers and the database layers. It allows for keeping other layers clean of business logic, and easier testing. These services implement the Zend\ServiceManager\ServiceLocatorAwareInterface, which greatly simplifies unit testing, as it is easier to replace concrete objects with mocks.

Let’s assume that we have a “post” service, which we can use to get the recent posts. The post service itself does not interact with the databse, but calls an AbstractTableGateway which does all the database work. A test case for this post service, to avoid database calls, should mock the AbstractTableGateway, and use the ServiceManager to replace the concrete implementation with the mock object. An example test case for this post service could look something like this:

<?php
namespace BlogModule\Service;
use PHPUnit_Framework_TestCase as TestCase;
use Zend\ServiceManager\ServiceManager;
use Zend\Db\ResultSet\ResultSet;
use \Mockery as m;
class PostTest extends TestCase
{
    protected $postService;
    /**
    * @var Zend\ServiceManager\ServiceLocatorInterface
    */
    protected $serviceManager;
    public function setup()
    {
        $this->postService = new Post;
        $this->serviceManager = new ServiceManager;
        $this->postService->setServiceLocator($this->serviceManager);
    }
    public function testGetRecentPosts()
    {
        $mock = m::mock('Blog\Model\Table\Post');
        $this->serviceManager->setService('blogModelTablePost', $mock);
        $result = array(
            array(
                'id' => 1,
                'title' => 'Foo',
            ),
        );
        $resultSet = new ResultSet;
        $resultSet->initialize($result);
        $mock->shouldReceive('getRecentPosts')
            ->once()
            ->andReturn($resultSet);
        $posts = $this->postService->getRecentPosts();
        $this->assertSame($posts, $resultSet);
    }
}

On line 18 we set the service manager to be used with the post service, on line 22 we create a mock object, and on line 23 we set that mock object in the service manager. We set some expectations on the mock object - what method should be called, how many times and what should it return. Finally we call the actual method that is being tested on the post service and assert that the returned result is correct.

Testing the database layer

For testing the database layer, that is the AbstractTableGateway implementations, I use a little… trick. I don’t actually test what is returned from the database, but that the correct Sql\Select objects are being called, with the correct parameters in a correct order. This, in turn, means that I trust the underlying Zend\Db code that in the end, it will assemble the correct SQL queries, but I also don’t have to bother with setting up a test database, and also the tests run faster, as they don’t actually call the database. An example test case, continuing our example of getting recent posts:

<?php
namespace Blog\Model\Table;
use PHPUnit_Framework_TestCase as TestCase;
use Zend\ServiceManager\ServiceManager;
use Zend\Db\Sql\Select;
use \Mockery as m;
class PostTest extends TestCase
{
    protected $postTable;
    protected $select;
    protected $tableName = 'blog_posts';
    public function setup()
    {
        $adapter = $this->getAdapterMock();
        $this->postTable = new Post($adapter);
        $this->select = m::mock(new Select($this->tableName));
        $this->postTable->setSelect($this->select);
    }
    public function testGetRecentPosts()
    {
        $this->select->shouldReceive('from')
            ->once()
            ->with($this->tableName)
            ->andReturn($this->select);
        $this->select->shouldReceive('where')
            ->once()
            ->with(array('published = ?' => 1))
            ->andReturn($this->select);
        $this->select->shouldReceive('order')
            ->once()
            ->with('id DESC')
            ->andReturn($this->select);
        $this->select->shouldReceive('limit')
            ->once()
            ->with(10)
            ->andReturn($this->select);
        $this->postTable->getRecentPosts();
    }
}

Here we create a mock adapter (the getAdapterMock method can be seen in this gist), and use that mock adapter in our AbstractTableGateway implementation. We also create a mock Sql\Select object and we set expectations on that mock Select object. As I said, this way of testing might not be the best way out there, but it did help me catch a bug where I failed to add the where clause on the actual Select object. Yey for Mockery! Oh, and please do note that the adapter mock might not work in all cases, but again, so far it worked nicely for me.

One other thing would probably be interesting to show how to test, and that’s the action controllers, but I haven’t got around to write any controllers yet, so I’ll probably leave that for part 2. Or you could do it for homework.

Happy hackin’!

Tags: mockery, modules, testing, unit test, zend framework 2.
Categories: Development, Programming, Software.

Working with custom view helpers in Zend Framework 2

by Robert Basic on September 11, 2012.
Heads-up! You're reading an old post and the information in it is quite probably outdated.

Zend Framework hit a big milestone as version 2 was released last week. Sadly, I didn’t have time to contribute to it, or even to poke around it much. I decided to slowly, as time permits, port this blog to ZF2; it should be a good enough learning playground.

I took the skeleton application, made it even skinnier by throwing out some (for me) unneeded parts and just put it all besides my old ZF1 code. Note: I think it could be possible to have a ZF1 and a ZF2 app run side by side, something like Stefan did for Symfony1 and Symfony2. Need to investigate on this. The first problem I ran into was using custom view helpers, especially view helpers that are more general and don’t fit into one specific module. Where to put the code? How to access them in views? The second problem was how to access the service manager from a view helper? And the third problem was how to tell the helper to use a specific value when inside a specific module?

Custom view helpers

As I found out, custom view helpers can live in different places (at least two) - in the vendor/ directory, or in the module/ directory as a part of a module. Both ways are probably good solutions, but for me it’s way easier to use the custom view helpers when they are “packaged” as a module:

On the image you can see I put the helpers in a module called Hex. The module.config.php file is something like:

<?php
return array(
    'view_helpers' => array(
        'invokables' => array(
            'customHelper' => 'Hex\View\Helper\CustomHelper',
            // more helpers here ...
        )
    )
);

The Module.php file is completely basic, it just has the Module class, implementing the getConfig() and the getAutoloaderConfig() methods. Include the module in the application’s main configuration file (config/application.config.php) and now the customHelper can be simply called from the view files as:

<php echo $this->customHelper(); ?>

Service manager in a view helper

To access the service manager in a view helper, it needs to implement the ServiceLocatorAwareInterface and two methods, setServiceLocator() and getServiceLocator(). In code, this would be something like:

<?php
namespace Hex\View\Helper;
use Zend\View\Helper\AbstractHelper;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class CustomHelper extends AbstractHelper implements ServiceLocatorAwareInterface
{
    /**
     * Set the service locator.
     *
     * @param ServiceLocatorInterface $serviceLocator
     * @return CustomHelper
     */
    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
    {
        $this->serviceLocator = $serviceLocator;
        return $this;
    }
    /**
     * Get the service locator.
     *
     * @return \Zend\ServiceManager\ServiceLocatorInterface
     */
    public function getServiceLocator()
    {
        return $this->serviceLocator;
    }
    public function __invoke()
    {
        $serviceLocator = $this->getServiceLocator();
        // use it at will ...
    }
}

Now, if you call getServiceLocator(), you’ll actually get the Zend\View\HelperPluginManager which gives access to other view helpers. If you want to access the “application wide” service locator, you need to call getServiceLocator() again on the HelperPluginManager. Confused yet?

<?php
// first one gives access to other view helpers
$helperPluginManager = $this->getServiceLocator();
// the second one gives access to... other things.
$serviceManager = $helperPluginManager->getServiceLocator();

Module specific values in view helpers

The problem (a bit simplified): how to tell the view helper to show “Welcome to my site!” on all routes/modules, except for the blog module, where it should show “Welcome to my blog!”. This one was the trickiest, as it can be solved in way too many ways. I first tried 2-3 different approaches, but they either didn’t work at all, or were just plain ugly hacky solutions. The final solution came to me when I answered a different question: what would be the easiest way to unit test this code? First, the custom view helper:

<?php
namespace Hex\View\Helper;
use Zend\View\Helper\AbstractHelper;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class Greeter extends AbstractHelper implements ServiceLocatorAwareInterface
{
    protected $message = null;
    /**
     * Set the service locator.
     *
     * @param ServiceLocatorInterface $serviceLocator
     * @return CustomHelper
     */
    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
    {
        $this->serviceLocator = $serviceLocator;
        return $this;
    }
    /**
     * Get the service locator.
     *
     * @return \Zend\ServiceManager\ServiceLocatorInterface
     */
    public function getServiceLocator()
    {
        return $this->serviceLocator;
    }
    public function setMessage($message)
    {
        $this->message = $message;
        return $this;
    }
    public function getMessage()
    {
        if ($this->message === null) {
            // for example, get the default value from app config
            $sm = $this->getServiceLocator()->getServiceLocator();
            $config = $sm->get('application')->getConfig();
            $this->setMessage($config['message']);
        }
        return $this->message;
    }
    public function __invoke()
    {
        $message = $this->getMessage();
        return $message;
    }

And the blog module specific part, where we hook to the “preDispatch” event:

<?php
namespace Blog;
class Module
{
    public function onBootstrap($e)
    {
        $eventManager = $e->getApplication()->getEventManager();
        $eventManager->attach('dispatch', array($this, 'preDispatch'), 100);
    }
    public function preDispatch($e)
    {
        $matchedRoute = $e->getRouteMatch()->getMatchedRouteName();
        // check for the matched route
        // and change the greeter message if needed
        if ($matchedRoute == 'blog') {
            $moduleConfig = $this->getConfig();
            $sm = $e->getApplication()->getServiceManager();
            $helper = $sm->get('viewhelpermanager')->get('greeter');
            $helper->setMessage($moduleConfig['message']);
        }
    }

And that would be it. I think.

Happy hackin’!

Tags: custom, php, view helpers, zend framework 2.
Categories: Development, Programming, Software.

Contributing to Zend Framework 2

by Robert Basic on November 10, 2011.
Heads-up! You're reading an old post and the information in it is quite probably outdated.

Today a pretty big news hit the interwebs: as of today, the CLA is not required any more to contribute to Zend Framework 2! This means anyone can issue pull requests and submit patches to the new version. Note that if you want to contribute to Zend Framework 1, you still need a signed CLA. I’ve decided to write a quick post with additional information and links, to make it easier getting started with the contributions!

Back in July I wrote a post on helping out with Zend Framework 2, so consider this post as a second part of that post ;)

The development is on git. The original repo is http://git.zendframework.com/?a=summary&p=zf, while the one on Github is a mirror which gets updated twice a day. Not that it matters much, as everyone forks the Github version and sends pull requests against that.

The issues are kept on a Jira instance: http://framework.zend.com/issues/browse/ZF2. Please make sure you are actually on the Zend Framework 2 project, as we have a separate project for ZF 1. Create an account on Jira and off you go. If I’m not mistaken, it is connected to the ZF wiki, so you can use that too.

All ZF2 related stuff on the wiki is located in it’s own section. It’s full of goodies, so take your time to browse it.

We hold biweekly IRC meetings: every second Wednesday, 17:00 UTC. The next one is going to be on November 23rd. Prior to each meeting we set up an agenda, vote on it, decide who will be moderator and then just discuss whatever is there to discuss. The meetings are held on the #zf2-meeting channel, on Freenode. All agendas and logs from previous meetings can also be found on the wiki.

We have a separate #zftalk.2 IRC channel devoted to discussing all things ZF2!

Subscribe to the mailing lists; you’ll be especially interested in the “Contributors” section; all big and small things are discussed there.

A new “thing” introduced to the ZF ecosystem are the RFCs. We’re using those when a new architecture is discussed or a rewrite/refactor of an existing component is to be done.

New components need to go through a proposal process. The proposal process is rumoured to get an overhaul, but (hopefully!) it won’t be going away.

There is also a blog set up, so be sure to subscribe to the feed.

Great and exciting times are ahead of us and I welcome all new ZF contributors! :)

Happy hackin’!

Tags: cla, contributing, zend framework 2.
Categories: Development, Programming.

Helping out with Zend Framework 2

by Robert Basic on July 27, 2011.
Heads-up! You're reading an old post and the information in it is quite probably outdated.

OK, here are some tips and resources so you can start helping out and contributing to Zend Framework 2.0 :)

First, here’s a nice wiki page with some links on how to start with Zend Framework 2. Be sure to check out the Zend Framework 2.0 patterns tutorial slides and the webinar on the same topic (you need to log in to watch it, but the registration is free, so no excuses).

The development is happening on github, so that’s a nice starting point to get your hands dirty with some code. On the wiki there’s a Zend Framework Git Guide to get you started. Pay close attention to the “Working on Zend Framework” chapter.

As Matthew noted in this thread you can:

Fix unit tests!

Once you forked and cloned the github repo, cd to the zf2/tests directory and simply make the tests there pass! Of course, there are a lot of tests there, so you might want to start with something easy and small; for example I picked the Zend\Dojo component :P

Anyway, once you’re in the tests directory, just type:

robert@odin:~/www/zf2/tests$ phpunit --verbose Zend/Dojo

or:

robert@odin:~/www/zf2/tests$ phpunit --verbose Zend/Dojo/DojoTest.php

and watch the tests pass or fail. If they pass, good, if they fail, try to fix them and make them pass! I tell you, it’s fun! By using the “–verbose” flag you’ll get more (helpful) info about the tests.

Port Zend\Service

I haven’t look into it yet, so just quoting from the mailing list:

* Port Zend\Service classes that interest you to namespaces, new
exception usage, etc.

but I believe if you start from the tests for the services too, you should be all set!

Port ZF1 patches to ZF2!

Even if ZF2 is under development, ZF1 is still taken care of: that means, a lot of patches are present in ZF1 which are not in ZF2 (cause they were added after ZF2 branched off of ZF1, obviously…). Some patches will probably not be needed thanks to the rewrite, but some patches will be! So head over to the issue tracker, search for recently (where recently is, say… this year?) resolved and fixed issues, see if they have a patch attached, if yes, open the patch, see if that patch is already in ZF2, if not, add it, issue a pull request, move on to the next issue.

Play with the existing code!

The official Zend Framework Quickstart is also on github, with different features on different branches! Fork it, clone it, test it, make it, break it, fix it… I myself am rewriting a ZF1 based application to ZF2, so you can have a look at that too!

I have also created a few gists about using the new helper loaders/brokers/plugins.

That’s it for now, if I remember/find anything else, I’ll update the post. Of course, if you have to add something, fire away! :)

Happy hackin’! :)

Tags: contribute, contributing, help, zend framework, zend framework 2.
Categories: Development, Programming.