Behavior Driven Testing with Zend Framework

Published on January 27, 2012

Codeception is testing framework in which all tests are written in a single descriptive manner. It's aim is to make tests easy to read, easy to write and easy to debug. Every single test you write can be run either in Selenium, in PHP Browser emulator, or as a functional test for Zend Framework. Today we will look how Codeception can be used for testing your Zend application.

Most of CRUD applications use forms for creating or editing content. It's hard to test every form on site after each release manually. But we will automate this process. For testing Zend applications you probably used it's Zend_Test_PHPUnit class, which is build on top of PHPUnit's TestCase. Codeception is built on top of PHPUnit too. And takes similar approaches from Zend_Test_PHPUnit_ControllerTestCase. But commands available in tests being made intuitively simple and much more human friendly then they are in Zend_Test_PHPUnit.

We take a code from Zend_Test_PHPUnit tutorial:

<?php
// Zend_Test_PHPUnit
$this->request->setMethod('POST')->setPost(array(
'username' => 'foobar',
'password' => 'foobar'
));
$this->dispatch('/user/login');
$this->assertRedirectTo('/user/view');
$this->resetRequest()->resetResponse();

$this->request->setMethod('GET')->setPost(array());
$this->dispatch('/user/view');
$this->assertQueryContentContains('h2', 'User: foobar');
?>

and reproducing it for Codeception:

<?php
// Codeception
$I->amOnPage('/user');
$I->submitForm('form#loginForm', array('username' => 'foobar', 'password' => 'foobar'));
$I->seeInCurrentUrl('/user/view');
$I->see('User: foobar', 'h2');
?>

It's only 4 lines long, but it does the same as the test above. It tests logging in on site, nothing more, nothing less. We can expect user is logged in if he was moved from '/user' page, to '/user/view' and username is in Heading2 element of that page.

Codeception won't perform asserts for application internals as module/controller/action, as this is not natural to bound functionality into one place. A small refactoring will completely break a test, even if application is running perfectly. For the same reasons Codeception doesn't provide analog for assertQueryCount or assertQuery, because they test a markup probably unseen to user. If a element on page has changed a test will fail, still application can work perfectly. We are testing only elements user can interact with and user can see. This makes tests more stable and drives us to less false negative results.

All the assertXXXX commands is replaced with natural 'see' commands.

  • see - checks if text or element with text is on page
  • seeInCurrentUrl - checks if a url contains specified value
  • seeLink - checks link exist on page
  • seeInField
  • seeCheckboxIsChecked
  • etc...

This commands can accept either CSS locators or element names.

With Codeception you can write tests that will be executed inside a Zend Framework, but will simulate user actions with less technical code. As every test should be readable and thus simple definitions in terms "I do that", "I see this" are better to understand. Especially, if a test is read by new developer.

Today we are going to write tests for open source blog application Lilypad-Zend-Framework-Blog. We assume you already have Zend Framework intalled.

It can be taken from GitHub:

git clone git://github.com/Codeception/ZFBlog.git

Set up database and configure application/configs/application.ini to access it. Default settings are:

resources.db.adapter = "PDO_MYSQL"
resources.db.params.host = "localhost"
resources.db.params.username = "root"
resources.db.params.password = ""
resources.db.params.dbname = "zfblog"

Database should be populated with zend_blog.sql dump from the project root.

To start covering it with tests Codeception should be installed.

Run bootstrap command from root of ZFBlog:

$ codecept bootstrap
$ codecept build

This will create a default test suites. Now some steps for configuration should be done.

For interacting with Zend Framework a ZF1 module is used. It should be enabled in functional tests configuration: tests/functional.suite.yml. For database repopulation after each step add Db module too.

class_name: TestGuy
modules:
  enabled: [ZF1, Db, TestHelper]

We use default settings for ZF1 module to connect to ZFBlog application. We use 'testing' environment and 'application.ini' stored in it's standard place: 'application/configs/application.ini'. But Db module requires additional configuration. We need schema and default data was recreated for each test run. We have database dump, a file named zend_blog.sql in root of project. We should point Codeception to use it for database repopulation. Now update a codeption.yml config in project's root and set proper db credentials.

paths:
    tests: tests
    log: tests/_log
    data: tests/_data
    helpers: tests/_helpers
settings:
    bootstrap: _bootstrap.php
    suite_class: \PHPUnit_Framework_TestSuite
    colors: true
    memory_limit: 1024M
    log: true
modules:
    config:
        Db:
            dsn: 'mysql:host=localhost;dbname=zfblog'
            user: 'root'
            password: ''
            dump: zend_blog.sql

We configured Db credentials and database dump being used. Now let's write some tests. In tests/functional let's create file CreateBlogCept.php:

<?php
$I = new TestGuy($scenario);
$I->wantTo('create new blog post');
$I->amOnPage('/admin');
$I->see('Blog Editing');
$I->click('Add new blog');
$I->see('Add new blog');
?>

Now a test can be run with command.

$ codecept run functional

And here is the expected result.

Codeception PHP Testing Framework v1.0.1
Powered by PHPUnit 3.6.4 by Sebastian Bergmann.

Suite functional started
Trying to  create new blog post (CreateBlogCept.php) - Ok


Time: 2 seconds, Memory: 21.00Mb

OK (1 test, 2 assertions)

To get detailed information of what steps were taken in test, run this command with --steps option. And this is what will be printed:

Trying to  create new blog post (CreateBlogCept.php)
Scenario:
* I am on page "/admin"
* I see "Blog Editing"
* I click "Add new blog"
* I see "Add new blog"
  OK

Also, all executed tests, steps performed and a results of execution, will be written to 'tests/_log' directory.

Try to create your own test for editing post. I hope you will like new way of testing Zend Application. Use Codeception to make your applications stable and predictable.

Support for Zend2 is coming soon.

submit to reddit
Quick Start →


Write and execute a test for an existing app in less then a 5 mins! No additional tools required. 

Latest stable version

Codeception was started in November 2011, and released the first stable version 1.0 in January 2012. Based on Symfony2 Components, PHPUnit, Mink. Codeception is a mature and stable project, well-tested and documented. It's open-source and MIT licensed.

Join #codeception on FreeNode IRC.