Defining Fixtures

Automated tests need to be executed many times. To ensure the testing process is repeatable, we would like to run the tests in some known state called fixture. For example, to test the post creation feature in a blog application, each time when we run the tests, the tables storing relevant data about posts (e.g. the Post table, the Comment table) should be restored to some fixed state. The PHPUnit documentation has described well about generic fixture setup. In this section, we mainly describe how to set up database fixtures, as we just described in the example.

Setting up database fixtures is perhaps one of the most time-consuming parts in testing database-backed Web applications. Yii introduces the CDbFixtureManager application component to alleviate this problem. It basically does the following things when running a set of tests:

  • Before all tests run, it resets all tables relevant to the tests to some known state.
  • Before a single test method runs, it resets the specified tables to some known state.
  • During the execution of a test method, it provides access to the rows of the data that contribute to the fixture.

To use CDbFixtureManager, we configure it in the application configuration as follows,

return array(
    'components'=>array(
        'fixture'=>array(
            'class'=>'system.test.CDbFixtureManager',
        ),
    ),
);

We then provide the fixture data under the directory protected/tests/fixtures. This directory may be customized to be a different one by configuring the CDbFixtureManager::basePath property in the application configuration. The fixture data is organized as a collection of PHP files called fixture files. Each fixture file returns an array representing the initial rows of data for a particular table. The file name is the same as the table name. The following is an example of the fixture data for the Post table stored in a file named Post.php:

<?php
return array(
    'sample1'=>array(
        'title'=>'test post 1',
        'content'=>'test post content 1',
        'createTime'=>1230952187,
        'authorId'=>1,
    ),
    'sample2'=>array(
        'title'=>'test post 2',
        'content'=>'test post content 2',
        'createTime'=>1230952287,
        'authorId'=>1,
    ),
);

As we can see, two rows of data are returned in the above. Each row is represented as an associative array whose keys are column names and whose values are the corresponding column values. In addition, each row is indexed by a string (e.g. sample1, sample2) which is called row alias. Later when we write test scripts, we can conveniently refer to a row by its alias. We will describe this in detail in the next section.

You may notice that we do not specify the id column values in the above fixture. This is because the id column is defined to be an auto-incremental primary key whose value will be filled up when we insert new rows.

When CDbFixtureManager is referenced for the first time, it will go through every fixture file and use it to reset the corresponding table. It resets a table by truncating the table, resetting the sequence value for the table's auto-incremental primary key, and then inserting the rows of data from the fixture file into the table.

Sometimes, we may not want to reset every table which has a fixture file before we run a set of tests, because resetting too many fixture files could take very long time. In this case, we can write a PHP script to do the initialization work in a customized way. The script should be saved in a file named init.php under the same directory that contains other fixture files. When CDbFixtureManager detects the existence of this script, it will execute this script instead of resetting every table.

It is also possible that we do not like the default way of resetting a table, i.e., truncating it and inserting it with the fixture data. If this is the case, we can write an initialization script for the specific fixture file. The script must be named as the table name suffixed with .init.php. For example, the initialization script for the Post table would be Post.init.php. When CDbFixtureManager sees this script, it will execute this script instead of using the default way to reset the table.

Tip: Having too many fixture files could increase the test time dramatically. For this reason, you should only provide fixture files for those tables whose content may change during the test. Tables that serve as look-ups do not change and thus do not need fixture files.

In the next two sections, we will describe how to make use of the fixtures managed by CDbFixtureManager in unit tests and functional tests.

$Id$

Total 5 comments

#17441 report it
marcovtwout at 2014/06/12 05:31am
Examples for init scripts
#12342 report it
Demitri at 2013/03/14 05:12pm
Note, if you get an "unknown method" error when attempting to access fixture data

I discovered that (at least as late as Yii framework v1.1.9) if you try to access a fixture model, by alias, and the alias does not exist, an "unknown error" method will be thrown. This drove me crazy at first, but then I realized the alias I was trying to access was off by the capitalization of a letter, and after correcting that, it worked just fine.

So, don't let it discourage you. It DOES work; it just isn't giving a helpful error message when there's a typo in the alias.

#11325 report it
Francis.TM at 2013/01/06 02:51am
the methods in fixture init scripts

According to the source code of CDbFixtureManager, it required the init script in CDbFixtureManager::resetTable() method, so that means you can call any public, protected and private methods of CDbFixtureManager, and also the $tableName variable.

#8670 report it
Eduardo Leiva at 2012/06/18 12:16pm
Exception: Unknown property 'countries' for class 'ProviderTest'.

I found that the fixture files must be in lowercase. Hope this helps someone. bye.

#2957 report it
Mike at 2011/03/02 04:06am
User phpMyAdmin to create fixture arrays

Tip: If you have large tables and a database that contains some sample data, you can use phpMyAdmin to help creating the fixture arrays. It provides an option to export table data as PHP array.

Leave a comment

Please to leave your comment.