CookieMonster's avatar

Does unit test match the actual data in order to pass?

I wrote a unit test to get all the listings of my concert like below:

 /** @test */
    public function user_can_view_all_concert_listing(){
        $this->withoutExceptionHandling();
        //Given we have a user, when we visit home page
        $concert = Concert::factory()->create();

        //If we visit the concert page
        $response= $this->get('/concerts');

        //We should be able to view all concert listing
        $response->assertSee($concert->title);
    }

By using factory, the title generated above is random each time the phpunit is run. And when I fetch the actual data in my database(from the controller) with hardcoded values and populate into my index.blade like below:

<body>
    @forelse ($concerts as $concert)
        {{$concert->title}}
    @empty
        
    @endforelse
</body>

The test case passed with {{$concert->title}} being present in the view. I guessed the part I am confused or overcomplicate things is the assertSee should check what value of the title is provided by the factory itself while my title in my view is difference than the value of what assertSee checks and compared.

In this case, why does the test still succeed?

0 likes
6 replies
SilenceBringer's avatar

@nickywan123 so, you have concert (generated by faker), and when you visit the page - you see it's title on the page. everything works as expected. Which part is confusing for you?

CookieMonster's avatar

The value of the title. Let's say if the test fails, it would say something like it could not see title "Lorem ipsum...." and when I pass the actual data received from my database to my view, say the title is 'Bon Jovi...' then the test passed.

So I am confused that doesn't the unit test assertion checks the title generated by the faker matches the title retrieved by the database?

Tray2's avatar

Let's walk through your code.

//This line creates a concert in the database using the ConcertFactory
$concert = Concert::factory()->create();

//Here you load the page with all your concerts
$response= $this->get('/concerts');

//In the response we look to see if the concert you created in the database is present.
$response->assertSee($concert->title);

In your controller you have something like

public function index()
{
	return view('concerts.index')->with(['concerts' => Concert::all()]);
}

What your Factory generates is what you test for in the view.

CookieMonster's avatar

Isn’t what the factory generate like a separate entity as it creates the concert into the memory instead of the actual database?

So my confusion is just what the factory generates is entirely different than what is inside my db since every time the unit test uses a database migration fresh.

Tray2's avatar
Tray2
Best Answer
Level 74

When you use the create method on the factory it stores it in the database.

$concert = Concert::factory()->create();

It refreshes the database for each test. So if the title is "Charles" on the first run of the test it checkes for "Charles"

$response->assertSee($concert->title);

On the next run the title is something totally different and the test will check for that.

If you want to just make fake data with your factory you use the make method.

$concert = Concert::factory()->make();

The make method will not store anything in the database. The make method is often used when you are testing your create routes. While the create is often used when you want to store data in the database for later manipulation in your test, such as update, delete or when you want to test that certain data is in a view like you done in your test.

Please or to participate in this conversation.