Symfony. Improving your tests with DoctrineFixturesBundle

Create fake data for your tests with the DoctrineFixturesBundle bundle

Gerardo Fernández
Aug 21, 2019 · 7 min read

One of the most tedious things we have to face when we write the tests of our application is the generation of test data.

For example, suppose we want to write the tests related to the web blog we are developing. In order to perform certain tests, we probably need that in the database there are already entities created so that we can navigate through them or test the different actions associated with them.

The simplest option we have for this is to directly create that data from our Test class, something that in the long run is not maintainable, because we would end up with a large amount of repeated code (at the moment we have several dependent entities, one of the others) and that would “dirty” the class itself.

This is where DoctrineFixturesBundle appears, which will greatly simplify this whole process. Lets go see it!


Installation

As I commented in the introduction of the article, DoctrineFixturesBundle allows the insertion of test data into our database in order to perform tests or other actions. In addition, it is compatible with any database with which it is Doctrine (MySQL, SQLite …)
To install this bundle in our project (assuming you are using version 4 of Symfony) we will use composer:

Whose recipe will perform the rest of the actions necessary to leave the bundle configured, although it never hurts to make sure that the following line has been added to our bundles.php file:


Writing our first Fixture

Once the bundle is installed, the DataFixtures folder will be added to our src folder, which is where we will create the classes for our Fixtures.

To create a Fixture class, all we need is to create it in the DataFixtures folder and extend the Fixture class provided by the bundle.

For example, suppose that as I said at the beginning we need to write the tests of a blog. What we will do is generate the PostFixtures class:

As you can see the code is quite simple. Within the load method belonging to the Doctrine\Bundle\FixturesBundle\Fixture class, what we will do is create 20 Post entities and execute the EntityManager flush method as we normally would.

Now, to load this data into a database, we will execute the following instruction from the command line:

and we are ready! We already have 20 test articles to perform our tests.

👁️! When executing that command the database is “purged”, so if you want to just add such data you must add the “append” option.

If you are wondering what the command does, the answer is very simple. Thanks to the autoconfigure option, Symfony is able to label the declared classes as services (which by default are all but those found in the Entity folders) depending on the interface they implement. In our case, since we are inheriting from Fixture, this abstract class implements the ORMFixtureInterface interface, so all the classes that inherit from it will be cataloged as Fixtures and therefore loaded by means of the previous command.


How to create dependent Fixtures

Before moving on to see how we can use Fixtures in our tests, I would like to talk about how we can create Fixtures that depend on others.

Returning to our example, it could be that each article belonged to a category, so we would also have to create a few categories in our test data.

Although we could generate these categories within the PostFixtures class itself, the most appropriate solution is to implement the DependentFixturesInterface interface so that we can relate some fixtures to others. Let’s see how to do it.

The first thing we will do is create our PostCategoryFixtures.php class:

Since PostCategoryFixtures we will use it later as a dependency of PostCategory, the code is somewhat different from that of the previous Fixture:

  • On line 21 I am using addReference to tell the bundle to add a reference to the Doctrine $category object so that it can be searched later. This method receives two arguments, the key to save the reference to the object and the object itself.
  • On line 11, I am creating a static method of home-grown in order to generate references for the objects created by Fixture based on the index of the loop.

Once this is done, we will modify our PostFixtures file to add the following:

The modifications are as follows:

  • On lines 9 and 11 this is importing the DependentFixtureInterface interface and implementing it.
  • On line 16 I am using the getReference method of the Fixture abstract class to retrieve a reference to an object in previously stored Doctrine. For this I need the object key, which I generate with the static method getReferenceKey of the PostCategoryFixtures class to which I pass an index between 0 and 4 (since I have only created 5 categories).
  • On line 30 I declare the dependencies of this Fixture, so that when loaded by means of the doctrine:fixtures:load command, the Fixtures indicated as dependencies are also executed.

Thanks to this, we can already generate test articles along with their relevant categories.


How to access services within a Fixture

Another of the situations that may arise when we are generating Fixtures is having to use a service, for example, if we are creating test users, we need to access the UserPasswordEncoderInterface service to encrypt their passwords.

This however is very easy to solve because all our Fixtures are (unless you have specified otherwise in the services.yaml file) services, so that we can inject dependencies in the usual way through the constructor:

Still, and in extreme cases we have two alternative solutions.

The first is to access the $this->container property of the Fixture itself but that has the limitation of not being able to return those services that we have declared as private.

The second is to implement the Symfony\Component\DependencyInjection\ContainerAwareInterface interface and use the Symfony\Component\DependencyInjection\ContainerAwareTrait trait within the fixture so that we also have access to $this->container.


Integrating fixtures with PHPUnit

Once we are familiar with the way we can create Fixtures, it is time to integrate the bundle with PHPUnit because, at the moment, to add our Fixtures to the database it is necessary to execute the command:

This causes that every time we run our tests we have to make sure that the Fixtures have been loaded, something that is very easy for us to ignore. Ideally, each test will be responsible for loading the Fixtures database with which it will work for which there are two alternatives.

LiipTestFixturesBundle

The LiipTestFixturesBundle bundle was originally integrated into the LiipFunctionalTestBundle bundle which adds a number of very interesting features to the PHPUnit suite such as running parallel tests or creating authenticated clients for end-to-end tests. However, as of version 3.0 the functionality of loading fixtures was separated to a separate bundle.

We will install it through composer:

This will allow us to add the Liip\TestFixturesBundle\Test\FixturesTrait trait to our test classes. Thus, in each method that defines a test we can use the loadFixtures method to specify which Fixtures we want to load when that test is to be executed:

In addition, this bundle presents some interesting functionality such as the possibility of excluding some tables from being purged when the fixtures are loaded or the option of adding the fixtures to the tables instead of having them previously purged.

Other solution

On the other hand, if you prefer not to resort to a third-party bundle you can always create the following class in your project:

This abstract class provides the addFixture method to the classes that extend it to add the Fixtures that we want to execute and the executeFixtures method to execute the Fixtures thus added. For example:

The only “but” in this way is that we must instantiate the Fixtures classes before passing them to the addFixture method (in our example new PostFixtures()) which causes that if we need to inject dependencies it is we who have to do it.


In summary…

As you can see, DoctrineFixturesBundle makes it very easy for us to write tests, also centralizing the creation of test data in one place. In addition, we can use this bundle to fill the database so that we can show how the application would look once there was data in it, something that is very useful in customer presentations.

I hope you liked the article. See you in the following!

¿Quieres recibir más artículos como este?

Si te ha gustado este artículo te animo a que te suscribas a la newsletter que envío cada domingo con publicaciones similares a esta y más contenido recomendado: 👇👇👇

Gerardo Fernández

Written by

Entre paseo y paseo con Simba desarrollo en Symfony y React

More From Medium

More from Gerardo Fernández

Related reads

More from Gerardo Fernández

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade