phplaravelphpunitlaravel-5.3

Using factory in PHPUnit provider fails


I'm trying to use a model factory to make models in a data provider. It works if i use the factory in the setup method or in the test directly, but if I try to use it in a data provider I get an error:

1) Warning

The data provider specified for MyClassTest::testSomeMethod is invalid.

Unable to locate factory with name [default] [App\Model\User].

The factory definition:

/** @var \Illuminate\Database\Eloquent\Factory $factory */
$factory->define(\App\Model\User::class, function (Faker\Generator $faker) {
    static $password;

    return [
        'id' => $faker->unique()->numberBetween(1, 10000),
        'email_address' => $faker->unique()->safeEmail,
        'remember_token' => str_random(10),
        'password' => $password ?: $password = bcrypt('secret'),
    ];
});

$factory->state(\App\Model\User::class, 'guest', function ($faker) {
    return [
        'role_id' => 9999,
    ];
});

My call to the factory:

factory(\App\Model\User::class)->states('guest')->make();

is it a bug from Laravel or am I missing something here?

Edit:

After some debugging, I found that factory definitions are not loaded before the data provider call, they where called (i.e. defined) when the setUp() method was called - which happens after data provider call -, so it can't find the factory in data provider.

So it seems to me that it is impossible to use factories in data providers (or any static method in the test class). Or there would be something I should do to define the factories in my data provider method!


Solution

  • I found an answer in a different question (caused by the same issue)

    So, this issue could be solved by calling $this->createApplication(); or $this->refreshApplication(); in the data provider method according to this answer, or by calling it in the constructor according to this answer

    the code will look like this

    public function dataProvider() {
        $this->refreshApplication(); // or $this->createApplication();
        $user = factory(\App\Model\User::class)->states('guest')->make();
    
        // ...
        // another code to generate data ....
        // ...
    
        return $someFakeData;
    }
    

    I tried that and worked, although I feel like its a workaround and not how things should work, any "cleaner" suggestions would be appreciated.