P-James's avatar
Level 12

Build a Laravel App With TDD - Episode 4, InvalidArgumentException: Unable to locate factory with name [default] [App\Project]

I am deep in bug town here, can anyone help? I am following the tutorial line by line and have got as far as the unit test in the episode: https://laracasts.com/series/build-a-laravel-app-with-tdd/episodes/4

I get the error:

  1. Tests\Unit\ProjectTest::test_it_has_a_path InvalidArgumentException: Unable to locate factory with name [default] [App\Project].

Some info:

The unit test is the second test in the video (starts @ 4:18), my code works fine for the first (feature) test, and the factory function works fine in tinker.

I have tried all kinds of different filepaths for 'App\Project', and also tried static Project::class type references.

My phpunit didn't run tests unless I prefixxed the word 'test', even when filtering to the exact test name, so I believe this may be due to an underlying phpunit version difference.

My unit test:

namespace Tests\Unit;

use Illuminate\Foundation\Testing\RefreshDatabase;
use PHPUnit\Framework\TestCase;

class ProjectTest extends TestCase
{

    use RefreshDatabase;

    public function test_it_has_a_path()
    {
        $project = factory('App\Project')->create();
        $this->assertEquals('/project/' . $project->id, $this->path());
    }
}

My Project factory

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\Project;
use Faker\Generator as Faker;

$factory->define(Project::class, function (Faker $faker) {
    return [
        'title' => $faker->sentence,
        'description' => $faker->sentence
    ];
});

My show method

public function show(Project $project)
    {
        return view('projects.show', compact('project'));
    }

My route

Route::get('projects/{project}', 'ProjectsController@show');

and the working feature test (for reference)

    public function test_a_user_can_view_a_project()
    {
        $this->withoutExceptionHandling();
        $project = factory('App\Project')->create();

        $this->get("/projects/" . $project->id)
            ->assertSee($project->title)
            ->assertSee($project->description);
    }
0 likes
12 replies
Nakov's avatar
Nakov
Best Answer
Level 73

@perdanjam the reason is because the unit test now extends from the PHPUnit testcase class instead of the framework testcase..

So you should avoid using factory in Unit tests. This was a change recently..

To be able to still use the factory, you should import this TestCase.

use Tests\TestCase;

And remove this:

use PHPUnit\Framework\TestCase;

And here is the change:

https://github.com/laravel/framework/commit/e30a0c979d98f2f1f7b6c565e4002734237a280b

35 likes
waffl's avatar

According to the conversation on the commit: https://github.com/laravel/framework/commit/e30a0c979d98f2f1f7b6c565e4002734237a280b#commitcomment-36691303

unit tests should be as fast as possible so any external influences that decrease their speed (booting the framework, resolving external dependencies) should be avoided ... You can use make:test to create a Feature test which boots up the framework or make:test --unit to create a Unit test that just extends the PHPUnit TestCase class so both scenarios are covered.

So I'm a bit confused, should factories ideally not be used in unit tests?

jozeperez's avatar

I was thinking the same thing myself. One using Laravel 7 :)

1 like
renoirtech's avatar

Thanks in advance! Looking forward for Laravel 7 TDD series!

Please or to participate in this conversation.