Sharing Fixture Between Tests

Sebastian Bergmann » 14 February 2010 » in New Features » 6 Comments

There are few good reasons to share fixtures between tests, but in most cases the need to share a fixture between tests stems from an unresolved design problem.

A good example of a fixture that makes sense to share across several tests is a database connection: you log into the database once and reuse the database connection instead of creating a new connection for each test. This makes your tests run faster.

PHPUnit 3.5 removes the fixture sharing feature of the TestSuite class. It was tedious to use this feature as it required the usage of a custom TestSuite class in addition to the test case class. Furthermore, its implementation was a "hack".

PHPUnit 3.4 introduced the setUpBeforeClass() and tearDownAfterClass() template methods that can be used in a test case class. These methods allow a much cleaner and simpler implementation of fixture sharing between tests of the same test case class:

<?php
class DatabaseTest extends PHPUnit_Framework_TestCase
{
    protected static $dbh;
 
    public static function setUpBeforeClass()
    {
        self::$dbh = new PDO('sqlite::memory:');
    }
 
    public static function tearDownAfterClass()
    {
        self::$dbh = NULL;
    }
}
?>

The example above uses the setUpBeforeClass() and tearDownAfterClass() template methods to connect to the database before the test case class' first test and to disconnect from the database after the last test of the test case, respectively.

It cannot be emphasized enough that sharing fixtures between tests reduces the value of the tests. The underlying design problem is that objects are not loosely coupled. You will achieve better results solving the underlying design problem and then writing tests using test doubles, than by creating dependencies between tests at runtime and ignoring the opportunity to improve your design.

Defined tags for this entry: ,

Trackback specific URI for this entry

6 Comments to "Sharing Fixture Between Tests"

Display comments as (Linear | Threaded)
  1. Noel Darlow
    14/02/2010 at 18:39 Permalink
    I'd strongly advise *never* to share a database connection in tests. Connection state such as affected rows, current error, currently used database etc allow a series of tests to contaminate each other if different instances of the tested class all use the same connection.

    Same applies to fixture creation: always use a separate connection to create/drop the fixture database, tables and data.

    New queries will obviously update everything ie previous state will only be factor if the test makes an assertion before a new query is performed with the shared connection. In practice the risk is low but it does exist. Data is precious and anything to do with data storage ought to go the extra mile.

    Reply

  2. Ralph Schindler
    10/03/2010 at 17:46 Permalink
    Noel,

    From a purely theoretical standpoint, you are absolutely correct. Realistically speaking though, MySQL, SQLite and and maybe Postgres database platforms you can target to have your tests run in a timely fashion. Some database platforms simply do not like creating connections (they are very slow at doing this), or executing DDL queries. Particularly, when running our tests (ZF) against Db2, Oracle, MSSQL- these tests take anywhere between 5mins and 20mins. Db2 on i5 takes around 4 hours.

    Since we have to test our Db abstraction layer against various databases platforms, it makes sense to craft them in such a way that makes running them as painless as possible. If that means sharing the connection, having to manually reset state, clear tables, and so on for each test, then we must do it because it's better to do that than have tests take too long to run to be useful.

    -ralph

    Reply

  3. Laurentiu
    07/05/2010 at 16:15 Permalink
    Hi Sebastian,

    Can you please tell me if you ever used PHPUnit with Maven for PHP? It seems there is a problem with that when using versions newer than 3.3.9. Is there anything I can do to use the latest version with Maven for PHP? I NEED that setUpBeforeClass() and tearDownAfterClass() and they are not in the 3.3.9 version.

    Thank you!

    Reply

  4. Sebastian Bergmann
    07/05/2010 at 16:18 Permalink
    I have never user Maven for PHP.

    Reply

  5. Laurentiu
    11/05/2010 at 12:08 Permalink
    Thank you, Sebastian. I'll have to deal with it in one way or another...

    Reply

  6. Laurentiu
    11/05/2010 at 12:48 Permalink
    Hi again, Sebastian.
    Maybe you can help me with a suggestion for my problem here?
    http://stackoverflow.com/questions/2773744/phpunit-maven-for-php-setupbeforeclass-not-called

    It's in fact the problem I described here but maybe you can give me a hint from the stacktrace? http://pastie.org/948377

    Thanks in advance!

    Reply

2 Trackbacks to "Sharing Fixture Between Tests"

  1. www.websdeveloper.com 15/02/2010 at 20:01
  2. www.websdeveloper.com 15/02/2010 at 20:01

Add Comment


To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

Submitted comments will be subject to moderation before being displayed.