Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

MrMister's avatar

Testing database with updated_at

I have feature test which passes in 99% cases but sometimes fails due to time update during test:

public function testCanUpdateOfferViaAPI()  {
    Passport::actingAs(
        factory(User::class)->create()
    );

    $attributes = factory(Offer::class)->create();
    $attributes->offer_name = $this->faker()->sentence;
    $response = $this->patch('/api/offers/' . $attributes->id, $attributes->toArray());

    $response->assertOk();
    $this->assertDatabaseHas('offers', $attributes->toArray());
}

It sometimes fails on last line when comparing record. It turns out that when time changes between create and update the record gets new time hence updated time don't match.

"updated_at": "2019-10-16 18:26:57", vs "updated_at": "2019-10-16 18:26:58",

How to test it correctly?

0 likes
3 replies
tykus's avatar
tykus
Best Answer
Level 104

Short answer: lock the time using Carbon::setTestNow('2019-10-17-09:45:00') - so that your timstamps will be consistent.

Longer answer:

If you are changing only the offer_name attribute, then why are you asserting against all of the attributes?

Also, your request payload is most likely not an accurate representation since you will almost certainly not be submitting created_at and updated_at attributes in the payload.

I typically prefer a test to communicate clearly rather than obfuscate the thing(s) that change. In any case, the updated_at and created_at properties are likely not the subject of your test.

public function testCanUpdateOfferViaAPI()
{
    Passport::actingAs(
        factory(User::class)->create()
    );

    $offer = factory(Offer::class)->create(['offer_name' => ''Original Name']);
    $response = $this->patch('/api/offers/' . $offer->id, ['offer_name' => 'Updated Name']);

    $response->assertOk();
    $this->assertDatabaseHas('offers', [
        'id' => $offer->id,
        'offer_name' => 'Updated Name',
    ]);
}

Whenever you are testing how you app handles a form, IMHO it is better not to use the array representation of a factory result - it most likely does not represent what a user will actually submit to your app. In my apps, I have a helper method in the test class to represent the form (in the happy-path scenario) ,which accepts overrides to test exceptional/invalid validation states:

public function validFormData($overrides = [])
{
    return array_merge([
        'offer_name' => 'Some Offer Name',
        // other form attributes and values
    ], $overrides);
}

In the test example case above, your request would look like this:

$response = $this->patch(
    '/api/offers/' . $offer->id,
    $this->validFormData(['offer_name' => 'Updated Name'])
);
3 likes
MrMister's avatar

I'm pretty new to both Laravel and testing so they are obviously not perfect. The purpose of the test was to check whether PATCH is working correctly and I'm able to update at least one attribute. In this case offer_name as it is mandatory attribute.

There is plenty of good points here but for now - the last line - to assert only on changed field is the answer for my problem.

Many Thanks!

tykus's avatar

No worries, please mark it solved if my answer helped.

Please or to participate in this conversation.