How to Test Zend Framework Applications with Codeception - Part Two

PHP  Testing 

In part two of the series on testing Zend Framework applications with Codeception, we see how to retrieve and test registered services using BDD-style testing


Part Two

“Codeception home page”

In part one of this series on testing Zend Framework applications with Codeception, we covered what Codeception is, how to install and configure it, and how to enable and configure the Zend Framework 2 module; finishing up by writing some basic acceptance and functional tests.

It wasn’t too intense, but did a solid job of getting us off to the right start with Codeception.

Here, in part two of the series we see how to retrieve and test registered services using BDD-style testing. This isn’t going to be an exhaustive look at every possibility of what’s available. Instead, what I’m going to do is show a simple set of examples which use two extra modules which come with Codeception and how they enable descriptive, BDD-style, tests.

What is BDD-Style Testing

But before we get too far along, what is BDD? Put simply, BDD, or Behavior Driven Development, as described by Wikipedia, is:

BDD is largely facilitated through the use of a simple domain specific language (DSL) using natural language constructs (e.g., English like sentences) that can express the behavior and the expected outcomes. BDD specifies that business analysts and developers should collaborate in this area and should specify behavior in terms of user stories, which are each explicitly written down in a dedicated document.

I tried to explain it to people over the weekend as a way of writing tests which can be read by people who aren’t technical in nature, or software developers specifically. Other people within a group or organisation, such as business analysts, can also write and read test specifications without knowing anything about software development.

It’s a form of testing that, the more I use it, the more I come to really like it. It makes applications self-documenting, because the way that the tests are written makes it simple to understand what each aspect of the application should do to be considered working.

Introducing Specify and Verify

Before we can start writing BDD-style tests with Codeception though, we need to ensure that we have two extra modules available. These are Specify and Verify. According to the official documentation:

Specify:

Allows you to write your tests in more readable BDD style, the same way you might have experienced with Jasmine. Inspired by MiniTest of Ruby now you combine BDD and classical TDD style in one test.

Verify:

Provides BDD Assertions for PHPUnit and Codeception. This is very tiny wrapper for PHPUnit assertions, that are aimed to make tests a bit more readable. With BDD assertions influenced by Chai, Jasmine, and RSpec your assertions would be a bit closer to natural language.

## Installing the Extra Modules

Specify is available by default, if you’re using the Codeception Phar file. But if you’ve installed Codeception using Composer, it’s not. To install the modules, you can either run the commands below:

composer require codeception/specify
composer require codeception/verify

Or you can add the following to the require-dev section of your project’s composer.json file and run composer update.

"codeception/specify": "*",
"codeception/verify": "*"

Generating the Unit Test

With the two libraries installed, let’s have a look at a unit test for a hypothetical service, which is a TableGateway class, which connects to a table, called tblvideo in a PostgreSQL (or other vendor’s) database.

As we didn’t cover unit tests last time, run the following command, similar to what you saw in last week’s post, to generate a unit test skeleton file:

php codecept.phar generate:test unit VideoTableServiceTest

This generates a file, located under tests/unit that looks like the code below. You can see that it has the same structure as we’ve come to know, providing a _before and _after method, which are analagous to PHPUnit’s setUp() and tearDown().

Note though that I’ve added a use statement for the Specify trait. This isn’t inserted by default. You’ll have to add this yourself.

use Codeception\Util\Stub;

class VideoTableServiceTest extends \Codeception\TestCase\Test
{
   use \Codeception\Specify;

   /**
    * @var UnitTester
    */
    protected $tester;

    // executed before each test
    protected function _before()
    {
    }

    // executed after each test
    protected function _after()
    {
    }
}

Testing a ServiceManager Service

Now let’s look at what we’ll be testing. I’ll assume that the service is configured using Abstract Factories, as I covered previously here on Master Zend Framework.

If you’re not familiar with abstract factories, you could also have used any of the other configuration options; those being factories, invokables, configuration classes, and initialisers.

Irrespective of how you’ve configured the service, let’s start by looking at how to retrieve it in Codeception. What’s really effective about the ZF2 module, is that it makes it simple to retrieve them, just as if you were doing so in the running application.

Now the manual suggests another way of retrieving them, but I wasn’t able to get that working in the test class.

Instead, I took the approach below, which first retrieves Codeception’s ZF2 module, then uses the grabServiceFromContainer() method, passing the name of the configured service, to retrieve the desired service. This is used to initialize a protected variable, called $table, which we’ll refer to in the tests.


/** @var \VideoHoster\Tables\VideoTable */
protected $table;

protected function _before()
{
    $this->table = $this->getModule('ZF2')
        ->grabServiceFromContainer('VideoHoster\Tables\VideoTable');
}

With the service now available, we’re able to test it. I want to stress that this one method takes so much overhead away from us and let us get down to testing so quickly, it’s a proverbial godsend. I was, admittedly, more than a bit skeptical that it would work so easily.But it does and it’s a dream!

Now let’s look at testing it. The method which I’ll be showing how to test, fetchActiveVideos(), retrieves and returns an array of the latest five videos which can then be iterated over. So let’s look at testing it.

Configuring Codeception’s Db Module

We’re going to use Codeception’s DB module in addition so doubly verify that the test results are valid.

To get that setup, in tests/unit.suite.yml, add the Db module to the list of enabled modules. Following on from the configuration in last week’s post, it should look like this:

class_name: UnitTester
modules:
    enabled:
        - Asserts
        - \Helper\Unit
        - ZF2
        - Db

Then you’re going to need to configure the module, otherwise it’ll complain of a missing configuration. To do so, in codeception.yml, add the following, then insert the values for dsn, user, and password relevant for your database:

modules:
    config:
        Db:
            dsn: ''
            user: ''
            password: ''
            populate: false
            cleanup: false

If this is your first time working with the Codeception’s Db module, the final two options, populate and cleanup, instruct the Db module to first populate the database before the tests are run, from a dump file which would be configured with the dump option, and to clean it up after the tests have finished running. As this isn’t a post on the Db module, I’ve set both to false, preloading the test database with a set of five records.

The Service Test

With that done, we’re now ready to look at the test. I’ve called it testVideoTableService, as that’s the purpose of it.

public function testVideoTableService()
{
    $this->specify("Video table is not the correct type", function () {
        verify(get_class($this->table))->equals('VideoHoster\Tables\VideoTable');
    });

Firstly, we’re going to test that the service is configured with the correct object, which must be an instance of VideoHoster\Tables\VideoTable. to do that, I’ve started by giving the test specification as the first parameter to the specify method.

For the body of the test, I’ve used an anonymous function. This will use the verify() method to test the assertion that the object has the correct class, by passing the object to PHP’s get_class method, then calling verify’s equal() method, and specifying the class which it should be.

This might not be the style that you prefer, but I find it almost 100% intuitive. You first specify the test condition, then specify how it should be comply. In addition to equals, the verify module offers a number of other methods, ones which you’d likely expect, including false, contains, greaterThanOrEqualTo, hasKey, notNull, and null.

Now let’s look at how testing the result of a method using this style. First, I’ll use the Db module to test that there are indeed five records in the database table. This is done as below, using the canSeeNumRecords() method, passing in the expected number of records, then the table to test.

We could also have been more specific, by using the canSeeInDatabase() method, specifying the table and the where clause criteria to filter down on. But canSeeNumRecords() is sufficient to verify that there are the number of records required.

    $this->tester->canSeeNumRecords(5, 'tblvideo');

Now let’s verify that there are the correct number of records using the fetchActive() use the service. As before, I’ll provide a natural language-like specification for what the test should verify.

Then, using the verify method, I’ll pass in the functionality to test, which is a call to the method fetchActiveVideos(), which is passed to PHP’s native count() method. Then, on that, I’ll call the equals method, passing in 5.

Note in this call, that I’ve passed a string as the first parameter, and the call to fetchActiveVideos() as the second. This is similar to the PHPUnit testing style, where you can pass in a string as the third parameter to the assert-family of methods, so that if the test fails, you can see what should have happened.

    $this->specify("Fetch the right number of videos", function() {
        verify(
          'Only 5 videos are returned',
          count($this->table->fetchActiveVideos())
        )->equals(5);
    });
}

Now we could have taken the PHPUnit style approach, as in the example below:

$this->assertEquals(count($this->table->fetchActiveVideos()), 5, 'Only 5 videos should have been returned');

Over To You

And that’s a great thing about Codeception. As it builds on PHPUnit, we could do that. We can mix and match the two different testing styles in the test file. But I find that the BDD style, using specify and verify is more intuitive, especially to non-technical staff, who may be reviewing the tests.

Do you use BDD-style testing in your testing regime? Have you found it to be more or less intuitive? Do non-technical people find the tests readable, meaningful, and/or helpful? Share your experience in the comments. I’d love to get your thoughts.


You might also be interested in these tutorials too...

Mon, Oct 19, 2015

How to Test Zend Framework Applications with Codeception

Testing is essential for creating reliable software. Whether you’re writing a small application for your local club or an application to back your startup, it needs test coverage to ensure it works properly. In this series, I show you how to test Zend Framework 2 applications using the comprehensive testing framework - Codeception.

Tue, Jul 5, 2016

What I Learned Building a Zend Expressive Application

Zend Expressive is an excellent framework for building modern applications; whether micro or enterprise-sized applications. But that doesn’t mean that it’s the easiest to get up to speed with. Today I’m going to share with you what I’ve learned, building applications using it.

Mon, Nov 30, 2015

Abstract Factories for Rapid Development

Zend Expressive, like the Zend Skeleton project before it, is a great platform for building robust, maintainable, highly scalable applications. But it’s generally not the platform you’d think of for rapidly application development. However one little technique can change all that. Today, let’s learn that technique and begin changing your perception.


Want more tutorials like this?

If so, enter your email address in the field below and click subscribe.

You can unsubscribe at any time by clicking the link in the footer of the emails you'll receive. Here's my privacy policy, if you'd like to know more. I use Mailchimp to send emails. You can learn more about their privacy practices here.

Join the discussion

comments powered by Disqus