Using Model Factory to make Test Data in Laravel 5.1

Access all tutorials in sprocket icon.

August 14, 2015 from author Bill Keck.

Making Test Data with Model Factory in Laravel 5.1*

We’re going to look at 2 ways to use the Model factory that ships with Laravel to create test records that we can play with for our Widget model.

Incidentally, if you want to see a cool video on this, check out the Laracast’s free video, Jeffery Way does an excellent job of teaching this. And just as a side note. I highly, highly recommend Laracasts as the best source of free and paid tutorials on Laravel anywhere. Our company even bought a company license so all our programmers can watch it. Jeffery is not paying me to say this, but I just can’t recommend it highly enough. You will love it.

Please note that we use the Widget model from our making a model in Laravel tutorial, so you should do that tutorial before moving on to this one.

Ok, let’s get started. Let’s open database/factories/ModelFactory.php. You can see that it comes with a factory method to seed the users table:



$factory->define(App\User::class, function ($faker) {
   return [
       'name' => $faker->name,
       'email' => $faker->email,
       'password' => str_random(10),
       'remember_token' => str_random(10),
   ];
});

You’ll note that we are using the faker library, which gets handed in as $faker. So this is all built for us out of the box and it’s incredibly simple. To run this, you would have had to run the initial migrations that come with Laravel 5.1, so that you have the database to insert the records to.

For now we are going to comment out this function and replace it with:



$factory->define(App\Widget::class, function ($faker) {
   return [
       'widget_name' => $faker->unique()->word,

   ];
});

To populate our widget_name column in our widgets table, we are going to use a faker word, making sure that it is unique, since we have that constraint on our db column.

You can check with the fzaninotto/Faker Git page for a full set of formatters you can play with, it’s pretty awesome.

Now to run this using the db:seed method via artisan, we first have to go to our database/seeds folder and open DatabaseSeeder.php, and change it to:



<?php

use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
use App\Widget;

class DatabaseSeeder extends Seeder
{
   /**
    * Run the database seeds.
    *
    * @return void
    */
   public function run()
   {
       Model::unguard();

       Widget::truncate();

       factory(Widget::class, 50)->create();

       Model::reguard();
   }
}

Inside the factory method, we hand in the appropriate model, in this case Widget, and we tell it how many records we want, in this case 50.

Then you would just go to your command line and, don’t do this yet, type the following:



php artisan db:seed

That’s pretty simple. Now if you did this, even though I said not to, and you want to get rid of the records, you could roll back the migration, assuming that you have not migrated anything else since you migrated up the widgets table:



php artisan migrate:rollback

The reason I recommended not using db:seed is there is a better way to do this, a tip I picked up from Laracasts. We can actually write a php unit test that will give us the option of whether or not to save the records, so we can see them first.

If you are completely unfamiliar with unit testing, don’t worry, I have a gentle introduction to unit testing that you can do before moving on. If you don’t normally follow TDD, it’s ok, but I would definitely recommend learning at least minimal testing practices and fortunately, Laravel makes this incredibly easy for you.

So I’m going to move assuming that you either know how to use php unit with Laravel or that you have checked out my tutorial and are ready to go.

So what we’re going to do is go into tests/ExampleTest.php and make a copy of that file named WidgetTest.php. Then let’s modify WidgetTest.php to the following:



<?php

use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use App\Widget;

class WidgetTest extends TestCase
{

   use DatabaseTransactions;

   /**
    * A basic functional test example.
    *
    * @return void
    */
   public function testWidgetFactory()
   {
       $widgets = factory(Widget::class, 50)->create();
       dd($widgets);
   }
}

So here we have made a simple test that calls the factory method to create our widget records. Since we are using:



use DatabaseTransactions;

The records won’t actually persist to the DB. And since we are using:



 dd($widgets);

The test will print out the objects.

So when you have this ready, just run php unit from the command line like so:



vendor/bin/phpunit

Like I mention in my php unit tutorial, if that path doesn’t work, try:



vendor/phpunit/phpunit/phpunit

Ok, so to persist the test records to the DB, just comment out Database Transactions like so:



// use DatabaseTransactions;

Now when you have the faker records in there, and you try to run the test a second time, you may get an error due to the unique constraint. That’s because faker doesn’t know what is already in your db. So if you need to run the test again, roll back the migration or drop the table manually first, then you can run it again.

And that’s it! You now have 2 ways to populate your DB with test data using model factories.

I hope you have enjoyed this tutorial and found it useful. Click on the sprocket icon at the top of the page to see all tutorials.

Please comment, share, and like if you can, thanks!

I don’t have a donate button, but If you would like to support my work and learn more about Laravel, you can do so by buying one of my books, Laraboot: laravel 5* For Beginners, I really appreciate it.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s