Pmizz's avatar
Level 1

Handling time assertions in testing with `assertDatabaseHas`

Part of our testing suite utilizes the Laravel method assertDatabaseHas.

We often use this for the entire record including time stamp columns like started_at or ended_at.

$this->assertDatabaseHas('my_foo', [
  'name' => 'foo',
  'category' => 'bar',
  'started_at' => $now,
]);

The problem is that within the test we define a timestamp like $now = Carbon::now() and use that as a parameter to create testing records via a http request that goes through the controller and a trait function. But then later on in the trait the functional logic uses something like this.

$nowTrait = FooModel::create([...])->created_at;

BarModel::create([
  'started_at' => $nowTrait,
]);

So when the assertDatabaseHas is called $now and $nowTrait are off by a second because of the run time between the test being run and invoking the trait through the controller and the route, and the assertion fails.

Is there some kind of way to ignore the time comparison on seconds and only use minutes. I am aware that can still cause a problem 1/60th of the time but I feel it's magnitudes less. Or does anyone else have a more eloquent solution.

I am aware we can just omit started_at and ended_at within the assertion but that's not satisfactory to me.

0 likes
2 replies
kevinbui's avatar
kevinbui
Best Answer
Level 41

Your feature is totally fine, one-second difference totally makes sense. I probably would remove the started_at assertion:

$this->assertDatabaseHas('my_foo', [
  'name' => 'foo',
  'category' => 'bar',
]);

If you still want to keep the assertion for the started_at field, considering various ways to interact with time, and Carbon::setTestNow() method.

Please or to participate in this conversation.