Laravel: Testing, Factory, and Events
Disable events while testing

I was testing my Laravel application. I usually write factories to create fake data on-fly while testing. While I was writing factory, I came across this error.
SQLSTATE[23000]: Integrity constraint violation: 19 NOT NULL constraint failed: post_statuses.user_id (SQL: insert into "post_statuses" ("status", "post_id", "user_id", "updated_at", "created_at") values (DRAFT, 1, ?, 2022-01-22 19:41:55, 2022-01-22 19:41:55))
Explaining the error: The field
user_idis not nullable in the database, but the value passed wasnull. So the database threw an error stating thatuser_idcan't be null.
I could not get my head around why user_id is null as I knew I passed the id as you can see from the code snippet.
// creating user
$user = User::factory()->create();
// Create post and status
PostStatusFactory::factory(5)
->for(Post::factory())
->forUser($user)
->create();
I even tried to hard code the data.
// creating user
$user = User::factory()->create();
// creating Post
$post = Post::factory()->create();
// creating PostStatus
PostStatus::factory()->create([
'post_id' => 1,
'user_id' => 1
]);
But, I was getting the same error.
Then, I remembered that I used eloquent event creating on PostStatus model. I used this event to add the logged-in user's id to the model.
creatingevent is dispatched before the model is created, which can modify or add new data to the model.
class PostStatus extends Model
{
// ...other codes
protected static function booted()
{
static::creating(function($postStatus){
$postStatus->user_id = Auth::id();
});
}
}
Events are dispatched even when the models are created using factories. As I was in the testing environment and had no authenticated user, thus Auth::id() gave me null.
Solving the error
Now I knew that the error would be solved if the events were not dispatched, so I disabled the event temporarily by using withoutEvents method.
// creating user
$user = User::factory()->create();
// Create post and status without event
PostStatus::withoutEvents(function() ($user) {
PostStatusFactory::factory(5)
->for(Post::factory())
->forUser($user)
->create();
});
Here, I temporarily disabled a single event on this occasion as I required them on other tests, but you can disable the events by using WithoutEvents traits.
use Illuminate\Foundation\Testing\WithoutEvents;
class PostTest extends TestCase
{
use WithoutEvents;
// other codes ...
}
Voilà! Problem solved. Finally, there was ✔️ ✔️ ✔️ in my test.
