CakePHP module for Codeception
PHP CSS Shell Other
Latest commit f2c4d14 Sep 14, 2016 @lorenzo lorenzo committed on GitHub Merge pull request #19 from cakephp/assert-emails
Assert emails

CakePHP 3 Codeception Module

Build Status License

A codeception module to test your CakePHP 3 powered application. Using Codeception with CakePHP opens up a whole new set of testing capabilities.

Front-end testing

(i.e. browser-based workflow tests)

Back-end testing

(i.e. direct, internal method tests)


From a CakePHP application, run the following from the command-line:

$ composer require --dev cakephp/codeception:dev-master && composer run-script post-install-cmd

If you are developing a plugin, add the post-install script to your composer.json first:

    "scripts": {
        "post-install-cmd": "Cake\\Codeception\\Console\\Installer::customizeCodeceptionBinary"

Once installed, you can now run bootstrap which will create all the codeception required files in your application:

$ vendor/bin/codecept bootstrap

This creates the following files/folders in your app directory:

├── codeception.yml
├── src
│   └── TestSuite
│       └── Codeception
│           ├── AcceptanceHelper.php
│           ├── FunctionalHelper.php
│           └── UnitHelper.php
└── tests
    ├── Acceptance.suite.yml
    ├── Functional.suite.yml
    ├── Unit.suite.yml
    ├── Acceptance
    │   ├── .gitignore
    │   ├── bootstrap.php
    │   └── AcceptanceTester.php
    ├── Fixture
    │   └── dump.sql
    ├── Functional
    │   ├── .gitignore
    │   ├── bootstrap.php
    │   └── FunctionalTester.php
    └── Unit
        ├── .gitignore
        ├── bootstrap.php
        └── UnitTester.php

As you might have noticed, the CakePHP implementation differs in a couple things:

  • uses CamelCase suite names (Functional vs. functional)
  • uses bootstrap.php, no underscore prefix (vs. _bootstrap.php)
  • uses src/TestSuite/Codeception for custom modules (helpers) (vs. tests/_helpers)
  • uses tmp/tests to store logs (vs. tests/_logs)
  • adds a .gitignore to never track auto-generated files
  • adds custom templates for various generated files using the codecept binary

To better understand how Codeception tests work, please check the official documentation.

Example Cept

$I = new FunctionalTester($scenario);
$I->wantTo('ensure that adding a bookmark works');
$I->submitForm('#add', [
    'title' => 'First bookmark',





Assert config key(/value) with seeInConfig($key, $value = null)

$I->seeInConfig(''); // checks only that the key exists
$I->seeInConfig('', 'CakePHP');
$I->seeInConfig(['' => 'CakePHP']);

Assert no config key(/value) with dontSeeInConfig($key, $value = null)

$I->dontSeeInConfig(''); // checks only that the key does not exist
$I->dontSeeInConfig('', 'CakePHP');
$I->dontSeeInConfig(['' => 'CakePHP']);


Insert record with haveRecord($model, $data = [])

This is useful when you need a record for just one test (temporary fixture). It does not assert anything and returns the inserted record's ID.

$I->haveRecord('users', ['email' => '', 'username' => 'jadb']);

Retrieve record with grabRecord($model, $conditions = [])

This is a wrapper around the Cake\ORM\Table::find('first') method.

$I->grabRecord('users', ['id' => '1']);

Assert record exists with seeRecord($model, $conditions = [])

This checks that the requested record does exist in the database.

$I->seeRecord('users', ['username' => 'jadb']);

Assert record does not exist with dontSeeRecord($model, $conditions = [])

This checks that the request record does not exist in the database.

$I->dontSeeRecord('users', ['email' => '']);




Load fixtures with loadFixtures($fixtures[, $fixture2, ...])

All the below forms are equivalent:

$I->loadFixtures('app.posts', 'app.tags');
$I->loadFixtures(['app.posts', 'app.tags']);
$I->fixtures = ['app.posts', 'app.tags'];

Assert CakePHP version with expectedCakePHPVersion($ver, $operator = 'ge')



Open page by route with amOnRoute($route, $params = [])

All the below forms are equivalent:

$I->amOnRoute(['controller' => 'Posts', 'action' => 'add']);
$I->amOnRoute('addPost'); // assuming there is a route named `addPost`

Open page by action with amOnAction($action, $params = [])

All the below forms are equivalent:


Assert URL matches route with seeCurrentRouteIs($route, $params = [])

All the below forms are equivalent:

$I->seeCurrentRouteIs(['controller' => 'Posts', 'action' => 'add']);
$I->seeCurrentRouteIs('addPost'); // assuming there is a route named `addPost`

Assert URL matches action with seeCurrentActionIs($action, $params = [])

All the below forms are equivalent:



Insert key/value(s) in session with haveInSession($key, $value = null)

$I->haveInSession('redirect', Router::url(['_name' => 'dashboard']));
$I->haveInSession(['redirect' => Router::url(['_name' => 'dashboard'])]);

Assert key(/value) in session with seeInSession($key, $value = null)

$I->seeInSession('redirect'); // only checks the key exists.
$I->seeInSession('redirect', Router::url(['_name' => 'dashboard']));
$I->seeInSession(['redirect', Router::url(['_name' => 'dashboard'])]);

Assert key(/value) not in session with dontSeeInSession($key, $value = null)

$I->dontSeeInSession('redirect'); // only checks the key does not exist.
$I->dontSeeInSession('redirect', Router::url(['_name' => 'dashboard']));
$I->dontSeeInSession(['redirect', Router::url(['_name' => 'dashboard'])]);