May 27, 2013
Table of contents:
Last week we started looking at Testing Laravel 4 Models. The validation tests we wrote for the User model are really easy to write because we are only testing very simply functionality. However, in the grand scheme of a full application, we are going to have to write some much more intricate tests.
One such example of this is when we are testing the relationships between Models. For example, in Cribbb, each Post belongs to a User. In order to create a Post, we need an instance of a User. In order to quickly instantiate an instance of a User, we can use a Fixture Replacement.
In this tutorial I’m going to be looking at using Fixture Replacement to quickly create instances of other Models within our tests.
Update: The following tutorial has been updated to reflect the 2.0 release of FactoryMuff (now called Factory Muffin).
Fixture Replacement is a way to quickly create instances of Model objects. So instead of actually having to create an instance of a certain Model, Fixture Replacement can quickly create one for you.
So instead of writing this each time you want to create an instance of the User model:
$user = new User();
$user->username = "philipbrown";
$user->email = "name@domain.com";
$user->password = "password";
$user->password_confirmation = "password";
You can simply write:
$user = FactoryMuffin::create("User");
The $user
Model object will be a real instance of the User Model filled with real test data, but it saves you from actually having to create it yourself.
The real power of Fixture Replacement is when you have Models that are related to other Models. For example, in order to create a Post, we need a User object. When you create an instance of a Model object using Fixture Replacement, the Model relationships are also created too. This makes Fixture Replacement perfect for writing automated tests.
Factory Muffin is a Fixture Replacement package that allows you to quickly create instances of Models. Factory Muffin is actually based on the very popular factory_girl gem, which I really like.
Factory Muffin is available as a package through Composer. To install Factory Muffin, add the following line to your composer.json
file:
{
"require-dev": {
"league/factory-muffin": "~2.0"
}
}
Next, run the following command from the terminal to pull the package into your project:
composer update
Before we can start using our fixtures in our tests, first we have to define a model factory so Factory Muffin knows exactly how you want your model object to look.
In order to create a factory, we can pass the model name and an array of attributes to the define()
method on the Factory Muffin Facade
:
League\FactoryMuffin\Facade::define("User", []);
The second argument is an array where you can specify how you want the properties of the model to be filled.
For example, if we wanted to set a user’s name, we could write the following:
League\FactoryMuffin\Facade::define("User", [
"name" => "firstName",
]);
If the users of our application can optionally have a profile picture, then we will want to be able to create fixtures that sometimes have a profile picture set. You can define this behaviour like this:
League\FactoryMuffin\Facade::define("User", [
"name" => "firstName",
"profile_pic" => "optional:imageUrl|400;400",
]);
Factory Muffin’s fake data is generated via the excellent Faker package. I’ve used Fake in a number of projects to generate fake data for populating databases, it is truly a fantastic package. To see the full spectrum of the fake data you can generate I would urge you to have a look at the GitHub repository.
As I mentioned in the introduction to this post, I find fixtures to be incredibly useful when I need to create an entity as well as it’s related entities.
For example, I need to create a Post
object and it’s related User
object, it would be useful if I could do that automatically, rather than manually creating and saving the two objects in the test.
Fortunately Factory Muffin can handle this for us.
To define a relationship in Factory Muffin, simply specify the factory option and pass the name of the related entity.
League\FactoryMuffin\Facade::define("Post", [
"user_id" => "factory|User",
]);
League\FactoryMuffin\Facade::define("User", [
"name" => "firstName",
"profile_pic" => "optional:imageUrl|400;400",
]);
Now if you create a new Post
instance, the returned object will automatically have an instance of User
through the relationship.
Now that we know how to define our fixtures, we are ready to start using them in our tests.
Create a new file under tests
called tests/factories/all.php
and copy the following code:
use League\FactoryMuffin\Facade as FactoryMuffin;
FactoryMuffin::define("Post", [
"user_id" => "factory|User",
]);
FactoryMuffin::define("User", [
"name" => "firstName",
"profile_pic" => "optional:imageUrl|400;400",
]);
Note: I’m aliasing the Facade
to FactoryMuffin
in the example above.
Create a new test file under tests
called UserTest.php
and copy the following code:
class UserTest extends PHPUnit_Framework_TestCase
{
}
The first thing we need to do is to load our factories so Factory Muffin knows how to generate new model instances:
public static function setupBeforeClass()
{
\League\FactoryMuffin\Facade::loadFactories(__DIR__ . '/factories');
}
The setupBeforeClass()
method will automatically include our factory definitions earlier so they are available during the tests.
We can also define a tearDownAfterClass()
method to clean up the objects that were created:
public static function tearDownAfterClass()
{
\League\FactoryMuffin\Facade::deleteSaved();
}
Now we can start using the fixtures in our tests:
public function testCreateNewPost()
{
$post = \League\FactoryMuffin\Facade::create('Post');
$this->assertInstanceOf('Post', $post);
$this->assertInstanceOf('User', $post->user);
}
And there you have it, using Factory Muffin, we can dramatically reduce the amount of code we have to write when writing tests. Fixture replacement makes quickly creating instances of models really easy, and it will save you a lot of hassle in the long run.
You will probably find that you require fixtures quite a bit when you are testing your application as a whole. Being able to very quickly generate model objects and their related entities is a blessing as it means you can create realistic objects on-the-fly without having to deal with that “infrastructure” in your tests.
This is a series of posts on building an entire Open Source application called Cribbb. All of the tutorials will be free to web, and all of the code is available on GitHub.