You could watch the videos that @jeffreyway has on testing. He demos a lot of examples.
Remember everything doesn't need testing.
Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.
Pretty certain I am missing something obvious in my code as I am still learning testing with Laravel:
The controller store method:
public function store(Request $request)
{
$products = $request->products; // Products model pivot table
$request->merge(['is_active' => $request->is_active == 'true']); // Checkbox, ensuring we have true or false
$validated = $request->validate([
'name' => 'required',
'level_id' => 'required',
'description' => 'required',
'is_active' => 'nullable',
'address' => 'nullable',
'address2' => 'nullable',
'country' => 'nullable',
'state' => 'nullable',
'city' => 'nullable',
'postcode' => 'nullable',
'website' => 'nullable',
'telephone' => 'nullable',
"contacts.*.name" => "nullable|string",
"contacts.*.email" => "nullable|email",
"contacts.*.user_id" => "nullable|integer",
"contacts.*.contact_type_id" => "integer",
]);
// Is there a better way to do these 2 steps?
$contacts = $validated['contacts']; // Put contacts into separate array
unset($validated['contacts']); // Remove contacts from validated data
$org = Organizations::create($validated); // Create new entry in Organizations
// Is there a better way to do these 2 steps?
$org->contacts()->delete(); // Delete any contacts that exist for this org
$org->contacts()->createMany($contacts); // Create new contacts for this org.
$org->products()->sync($products); // Sync (pivot table) products
return redirect(route('organizations.index'));
}
The above all works as expected. However, testing that contacts have been created is not currently working, as the organizations_id being added when calling createMany($contacts) is not available to the test:
/** @test */
public function can_create_org_with_contacts()
{
$this->signInAdmin();
$this->withoutExceptionHandling();
OrganizationLevels::factory()->create();
ContactTypes::factory()->count(2)->create();
$org = Organizations::factory()->make();
$contacts = Contacts::factory()->count(4)->make()->toArray();
$org->contacts = $contacts;
$this->post(route('organizations.store'), $org->toArray())
->assertRedirect(route('organizations.index'));
$this->assertDatabaseHas('contacts', $contacts[1]);
}
The result is
Failed asserting that a row in the table [contacts] matches the attributes {
"name": "Janet Lesch",
"email": "[email protected]",
"organizations_id": null,
"contact_type_id": 2,
"user_id": 1
}.
Found similar results: [
{
"id": "2",
"organizations_id": "1",
"contact_type_id": "2",
"user_id": "1",
"name": "Janet Lesch",
"email": "[email protected]",
"created_at": "2021-03-09 17:13:34",
"updated_at": "2021-03-09 17:13:34"
}
].
Questions:
The result of your test shows that the organizations_id's doesn't match (null vs 1).
You can test that your organization has 4 contacts, rather than testing that the database has the given contact.
$this->assertEquals(4, $org->fresh()->contacts()->count())
I think the following will also work, if you only want to test that the contact with given name was saved to DB, but then you are not testing that the contact was correctly inserted in DB with organization_id:
$this->assertDatabaseHas('contacts', $contacts[1]['name');
Also consider changing the 'organizations' model to singular, as would be the normal convention.
Please or to participate in this conversation.