
Testing and Test-Driven Development (TDD) are essential and challenging topics in programming. Especially the switch from just writing some tests to TDD can be tricky.
After using TDD for several years, I see three things you need to know to make it work.
1. You Need To Know What To Test
public function it_gives_successful_response_for_homepage()
{
$this->get('/')
->assertSuccessful();
}
In the following example, I test a custom factory class of mine. I want to ensure that the output of the create
method fits my expectations.
public function it_creates_new_post_file()
{
Storage::fake('posts');
$postPath = PostFactory::new()
->create();
$this->assertFileExists($postPath);
}
public function it_caches_posts_when_command_run()
{
$this->assertFalse(Cache::has('posts'));
$this->artisan(CachePostsCommand::class);
$this->assertTrue(Cache::has('posts'));
}
2. You Need To Know Your Stack
public function it_includes_video_player_component () {
// Arrange
$user = User::factory()
->withPurchasedProduct();
// Act & Assert
$this->actingAs($user)
->get(route('videos', $user->products->first()))
->assertSeeLivewire(VideoPlayer::class);
}); );
public function it_orders_player_videos() {
// Arrange
createProductVideos(3, new Sequence(
['title' => 'Outro', 'order_slot' => '3'],
['title' => 'Intro', 'order_slot' => '1'],
['title' => 'Middle', 'order_slot' => '2']
));
// Act & Assert
Livewire::test(VideoPlayer::class, ['productId' => Product::first()->id])
->assertSeeInOrder(['Intro', 'Middle', 'Outro']);
});
Note: Laravel Livewire has its own testing helper which I use to test Livewire components.
If I didn’t test this component in isolation, I would have to test the same things on every page I use this player.
That’s why I only ensure the component is used on the video page. Everything else will be tested in a separate component test.
When I start a new project, these are all things I already know, and they help a lot while writing tests before the implementation.
3. You Need To Change Your Workflow
Red 🛑
red stands for a failing test. This is also true for a new, empty test, and that’s where we start.
It is often a good idea to think about what you want to test first and write an empty function for each of them.
public function it_shows_posts_per_page()
{
}
public function it_shows_post_prev_and_next_buttons()
{
}
public function it_resets_pagination_after_search()
{
}
Green ✅
The next step is making your test Green, which means passing it. You must now implement your new feature, and the test will tell you if it works as expected.
This is a crucial step because there are many ways to make your test green. But we are only interested in the fastest one. We don’t care if the code is beautiful or SOLID or whatever. We want it to work, which is the most important thing.
Refactor ♺
Only after a test passes can we start thinking about how to improve the code. This could mean anything from code-styling to making it more readable or simple.
Because we already know that our first solution worked, we will immediately see if the new solution is failing. This will give you a lot of confidence for refactoring your code to your needs.
Conclusion
Test-Driven Development has become my default for coding for some years now. It helps me to focus better on what I really want to develop, without getting lost in details or other todos. Having tests also lets me sleep better at night when knowing my code works.