3 useful tips for writing Alice fixtures

Author: Leighton
Monday, June 13 2016

Alice fixtures can be a great help when you're writing some tests or even just filling up your system with dummy information. Here's some useful tips to keep in mind when writing fixtures with Alice.

Here at Viva IT we use Alice fixtures in a lot of our projects, mostly for the purpose of testing. We've encountered a few issues that others might not foresee if they jump straight in, so here's some things that'll help you keep things running smoothly without creating problems further down the line.

1. Keep things separate and specific

When you're using fixtures for testing purposes, it's a good idea to try and keep things separated and specific to what's being tested. It's a nice idea to have a bunch of fixtures that are used for all of your tests, but it eventually becomes a nightmare not only to manage but also to keep working. What we've moved on to doing is creating fixtures from the ground up for each test, so that we don't run into the problem of changing a single thing and having completely unrelated tests breaking. Another good idea would be to have some 'base' fixtures and templates that are set up without any objects being created (or as few as possible) so that they can be included in your test specific fixture files. It also makes the fixture files easier to work with, and makes fixing any failing tests a lot easier.

Here's a quick example:

# base_fixture.yml
AppBundle\Entity\School:
    school_template (template):
        location: gb
        funding: 100000

AppBundle\Entity\Student:
    child_template (template):
        age: 15

AppBundle\Entity\Principal:
    principal_template (template):
        age: 54
# many_children.yml
include:
    - base_fixture.yml

AppBundle\Entity\School:
    school_unique_names (extends school_template):
        name: School With Unique Names

AppBundle\Entity\Student:
    child_{1..100} (extends child_template):
        name (unique): <name()>
        schoolYear: 11

AppBundle\Entity\Principal:
    principal_1 (extends principal_template):
        name: <name()>
        school: '@school_unique_names'
# john_smith_exception.fail.yml
include:
    - base_fixture.yml

AppBundle\Entity\School:
    school_other_names (extends school_template):
        name: School With Other Names
        location: us

AppBundle\Entity\Principal:
    principal_john_smith (extends principal_template):
        name: John Smith
        school: '@school_other_names'

Using this method you can freely change john_smith_exception.fail.yml without worrying about breaking many_children.yml. You can also get rid of anything that isn't related to the current test, speeding your test suite up immensely once it inevitably grows in size.

2. Make good use of templates

Alice has a great section on Keeping Your Fixtures Dry that's well worth a read if you haven't read it yet. Taking advantage of Alice's template feature can save you a lot of time when you're creating multiple of the same type of object, especially if there's some complex or detailed information that needs to be added in. You can also mix and match with the templates, allowing you to write your fixtures faster.

It's a good idea to have a base template for each object which can then be extended upon. It seems simple if you know about the functionality, but the urge to just copy and paste can be strong at times to get things out of the way. It also allows for better organisation of your fixtures, which will help a lot when it comes to debugging.

3. Keep your fixtures readable

If you make sure that your fixtures are as readable as your code then it'll make your life so much easier when you have problems. Things like comments explaining 'magic numbers' are forgotten in a lot of fixtures for some reason, and there's no excuse. If a problem occurs because the object's type is set to 8721, it's going to be a real unnecessary pain to have to go into eight different files to figure out what it means when you could have just left a comment.

Making sure your file and object names stay relatively verbose is also something that can be incredibly useful. test1.yml and test2.yml might both be testing the same thing in different ways, but nobody's going to know unless you name them as such. We've recently adopted a naming convention of sorts, which helps us a lot when browsing through our tests that use fixtures:

feature_being_tested.any_modifiers.yml

which would change our test1.yml and test2.yml into something like grading.passing_grades.yml and grading.failing_grades.yml.

Safely escape Twig's json_encode() without using raw Services in Twig