One of the things I've found that can make controllers difficult to test in Zend Framework 2 is the use of controller plugins. Although it makes the functionality provided by the plugin itself easier to test, I found it makes it difficult to test the controller itself. In the past I've resorted to mocking the controller and in turn mocking the controller plugin as if it was a method.

However, I've looked into this a bit more and it looks like there's a better way. You can simply use the controller's controller plugin manager, and pop the required service in (i.e. the controller plugin - could be a mock or the actual plugin itself, depending on your needs). This simplifies testing a controller that uses plugins greatly. Consider this controller:

<?php

namespace Application\Controller;

use Zend\Mvc\Controller\AbstractActionController;

class MyController extends AbstractActionController
{
    public function indexAction()
    {
        $foo = $this->foo(); // is a controller plugin that returns something

        return ['foo' => $foo];
    }
}

And our controller plugin:

<?php

namespace Application\Controller\Plugin;

use Zend\Mvc\Controller\Plugin\AbstractPlugin;

class Foo extends AbstractPlugin
{
    public function __invoke()
    {
        return "Woo hello!";
    }
}

And then to write our test for this, we could do the following:

<?php

namespace ApplicationTest\Controller;

use Application\Controller\MyController;
use Application\Controller\Plugin\Foo;

class MyControllerTest extends \PHPUnit_Framework_TestCase
{
    public function testIndexActionReturnsFoo()
    {
        $fooMock = $this->getMockBuilder(Foo::class)
            ->setMethods(['__invoke'])
            ->getMock();

        $fooMock->expects($this->once())->method('__invoke')->will($this->returnValue('Hello world!'));

        $controller = new MyController();
        $controller->getPluginManager()->setService('foo', $fooMock);

        $returnValue = $controller->indexAction();

        $this->assertSame(['foo' => 'Hello world!'], $returnValue);
    }
}

You could substitute the mock in the example above with a real instance of the controller plugin without too much hassle.

I set up a working demo project on GitHub which you can clone here.