A quick and simple way to make your functional tests independent with Symfony and mysql

Having independent functional tests is a good practice recommended by many developers. It allows you save a great deal of time; and it is well known, time is money!

Why

If your tests are not independent, it means that the execution of one test can impact the result of the following tests. Dependent tests can in fact fail randomly depending on the order of execution.

I started working on a small project with a small amount of tests and I did not notice the problem at first. But as we added features, the number of tests increased significantly. And they started failing randomly. The bigger the project, the more difficult it is to understand why tests fail. We lost hours trying to find out the root cause of the failures. Indeed, the cause was not in the failing tests itself, but the failure was due to the execution of one test before. It thus took us a lot of time and energy to maintain our tests on a daily basis.

Therefore, we decided to solve the problem and make our tests independent in a quick and simple way : reset the database between each test to make them start with a clean set of data. We set one constraint: to not impact the performances !

Let’s practice

As I mentioned before, in order to make our tests independent we chose to reset the database before each test using a dump
file. Here are the two main steps of the process:

    • Create an sql dump from your test database: To run your functional tests, you need to create a database. Right after this
      set up, create a dump of it :
mysqldump -u $USER -h $HOST -p $PASSWORD $BDD_NAME > dump_db_test.sql
    • Reset your database before each test: Once the dump is created, we will use it to reset the database. You can create
      an AbstractBaseTestCase.php extending the \PHPUnit_Framework_TestCase. Every functional test file should extend this file. In this file, create a setUp() method which will be run before each of your tests. This method will execute the command to reset the database with the dump file created before :
abstract class AbstractBaseTestCase extends \PHPUnit_Framework_TestCase
    {
        public function setUp()
        {
            $importCommand =
        mysql -h mysqlHost -u mysqlUserName -p mysqlPassword mysqlDatabaseName < mysqlImportFilename;

            exec($importCommand);
        }
    }

Before executing one functional test, this method is executed and it cleans the database. The following test then uses a new set of data and the previous modifications of the database do not impact the running test.

Going further

  • As you may have noticed, each time you’re using a plaintext password in the command line, a warning is printed in the console.
    To avoid this you can set up the password as an environment variable.

    Export MYSQL_PWD=’mysqlPassword’
  • As a quick solution, we decided to use the same database for each test. It is possible to improve this model and use fixtures
    to load before each test only the ones needed to run the tests.

You liked this article? You'd probably be a good match for our ever-growing tech team at Theodo.

Join Us