Welcome to Abdul Malik Ikhsan's Blog

Unit and Functional testing Zend Framework 3 Controller with Kahlan 3.0

Posted in testing, Tutorial PHP, Zend Framework 2 by samsonasik on October 24, 2016

This post will cover unit and functional testing ZF3 Controller with Kahlan 3.0. For example, you have a ZF3 Skeleton application with an IndexController like the following:

namespace Application\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;

class IndexController extends AbstractActionController
{
    public function indexAction()
    {
        return new ViewModel();
    }
}

As usual, we need to require kahlan/kahlan:^3.0 via composer command:

composer require --dev kahlan/kahlan:^3.0 --sort-packages

You can then write the spec. Let’s write our spec inside module/Application/spec like the following structure:

module/Application/
├── config
├── spec
│   ├── Controller
│   │   ├── IndexControllerDispatchSpec.php
│   │   └── IndexControllerSpec.php
├── src
│   ├── Controller
│   │   ├── IndexController.php

if we are only have the 1 module, named Application module, we can define the spec and src path via kahlan-config.php like the following:

// ./kahlan.config.php
$commandLine = $this->commandLine();
$commandLine->option('spec', 'default', 'module/Application/spec');
$commandLine->option('src', 'default', 'module/Application/src');

Or for multi-modules, we can run parallel command that specify --spec and --src in command like the following:

vendor/bin/kahlan --spec=module/Application/spec --src=module/Application/src

in each iteration. If you’re using ant, you can write a build.xml for tasks definition:

<?xml version="1.0" encoding="UTF-8"?>
<project name="My Website" default="build">
    
    <!-- executable files directory definition -->
    <property name="toolsdir" value="${basedir}/vendor/bin/"/>
    <!-- module directory definition --> 
    <property name="moduledir" value="${basedir}/module/"/>

    <target name="build"
            depends="kahlan"
            description=""/>

    <target name="kahlan"
            description="Run kahlan">
        
        <parallel>    
        
            <!-- Application -->    
            <exec executable="${toolsdir}kahlan" failonerror="true" taskname="kahlan">
                <arg 
                    line="-spec=${moduledir}Application/spec/ 
                    --src=${moduledir}Application/src"/>
            </exec>
            <!-- Application -->
            
            <!-- other modules run test definition go here --> 
        </parallel>
        
    </target>

</project>

Unit testing

Let’s write the unit testing inside spec/Controller/IndexControllerSpec.php:

namespace ApplicationSpec\Controller;

use Application\Controller\IndexController;
use Zend\View\Model\ViewModel;

describe('IndexController', function () {
    
    given('controller', function () {
        
        return new IndexController();
    
    });
    
    describe('->indexAction()', function() {
        
        it('instance of ViewModel', function() {
            
            $actual = $this->controller->indexAction();
            expect($actual)->toBeAnInstanceOf(ViewModel::class);
            
        });
        
    });
    
});

That’s enough for IndexController::indexAction() unit test, nothing complex logic we need to accomodate as it only return the ViewModel instance, so we just need to check if return values is instance of ViewModel.

Functional Testing

Now, we need to make sure if the dispatch response of IndexController::indexAction() by open ‘/’ url that shown by user is the expected result, that show a welcome page, let’s do with spec/Controller/IndexControllerDispatchSpec.php:

namespace ApplicationSpec\Controller;

use Zend\Console\Console;
use Zend\Mvc\Application;

describe('IndexController Dispatch', function () {
    
    // setup the Application
    beforeAll(function () {
        
        Console::overrideIsConsole(false);
        $appConfig = include __DIR__ . '/../../../../config/application.config.php';
        $this->application = Application::init($appConfig);

        $events = $this->application->getEventManager();
        $this->application->getServiceManager()
                          ->get('SendResponseListener')
                          ->detach($events);

    });
    
    // dispatch '/' page tests
    describe('/', function() {
        
        it('contains welcome page', function() {
            
            $request     = $this->application->getRequest();
            
            $request->setMethod('GET');
            $request->setUri('/'); 
            
            // run app with '/' url
            $app =  $this->application->run();
            
            // expect actual response is contain
            // a welcome page
            expect(
                $app->getResponse()->toString()
            )->toContain('<h1>Welcome to <span class="zf-green">Zend Framework</span></h1>');
            
        });
        
    });
    
});

That’s it😉

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: