Wow... Two months! That's how long it took to complete this task. To be fair, a lot happened during this period, the birth of my newborn son being the main event! 🎉

I had a lot of fun developing this feature, and it was a lot of work, from figuring out how to properly develop Blade components for tables, rows, search, forms, etc., to architecting and test CRUD support for the teachers' account's repository. All of this while being sleep deprived - a consequence of having a newborn.

Although a CRUD isn't something new, I did end up taking the time to think about how tests should be made when we have a repository that already has its test suite, and how I should test the application layer (controllers, in this specific case). In the past, I would assert that the side-effects of a controller were indeed executed - like asserting that a user exists in the database after hitting the store endpoint - but that consequence is already tested in the repository tests. So, how could I test that a controller was programmed to interact with the repository without testing, again, that the repository worked?

The answer is mocking the repository. By adding mock assumptions in the integration tests of, in this case, the TeachersController, I did ensure that that controller was interacting correctly with the repository without actually executing the repository's methods. This is an example of how I did that:

/** @test */
public function it_stores_teacher(): void
{
    $payload = [
        'name' => $this->faker->name,
        'email' => $this->faker->safeEmail,
        'role' => UserRolesEnum::TEACHER,
    ];

    $this->mock(TeacherRepository::class)
        ->shouldReceive('store')
        ->once()
        ->with($payload['name'], $payload['email'], $payload['role'])
        ->andReturn(
            new User([
                'name' => $payload['name'],
                'email' => $payload['email'],
                'role' => $payload['role'],
            ])
        );

    $this->actingAs($this->director)
        ->post(route('accounts.teachers.store'), $payload)
        ->assertSessionHasNoErrors()
        ->assertRedirect(route('accounts.teachers.index'))
        ->assertSessionHas('message');
}

The cool thing is that even if the internal workings of the store() method of this repository change, this test isn't affected. It only gets affected if the public API changes.

Now that this second feature is done - you can check the PR here if you feel curious - it's time to move on to add support to manage courses.