If you ever tested an endpoint returning a collection of data and, for example, by default, you sort them by created_at
, you may have been struggling to check the correct order of the result. If you either created multiple data with User::factory()->count(3)->create()
or just a few User::factory()->create()
one after another, their timestamps will be pretty much the same, providing wrong results because the sorting will be wrong.
You have two solutions to solve this problem: the first one (ok, but not reusable) is to travel in time after each factory using Laravel's time-testing helpers:
$user = User::factory()->create();
$this->travel(1)->minutes();
$user2 = User::factory()->create();
$this->travel(1)->minutes();
$user3 = User::factory()->create();
dump($user1->created_at); // 2021-01-01 00:00:00
dump($user2->created_at); // 2021-01-01 00:01:00
dump($user3->created_at); // 2021-01-01 00:02:00
$this->getJson('/users')
->assertOk()
->assertJson(...);
Although this just works fine, it can be annoying when you need this logic in multiple tests. The smartest solution (recommended) is to use the Factory's callbacks with a bit of Carbon testing magic:
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
use Illuminate\Support\Carbon;
class UserFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = User::class;
/**
* Configure the model factory.
*
* @return $this
*/
public function configure()
{
return $this->afterCreating(function (User $user) {
Carbon::setTestNow(Carbon::now()->addMinute());
});
}
}
What we are doing here is telling Carbon to set the current time to "+1 minute" after each Factory creation. Then, in our test, we can get rid of those time travels:
$user = User::factory()->create();
$user2 = User::factory()->create();
$user3 = User::factory()->create();
dump($user1->created_at); // 2021-01-01 00:00:00
dump($user2->created_at); // 2021-01-01 00:01:00
dump($user3->created_at); // 2021-01-01 00:02:00
// Or...
$users = User::factory()->count(3)->create();
foreach ($users as $user) {
dump($user->created_at);
}
// 2021-01-01 00:00:00
// 2021-01-01 00:01:00
// 2021-01-01 00:02:00