TDD (Test Driven Development)
In this section, we'll cover Test Driven Development (TDD).
Let's run our dev server and see the current state of our Todo app.
Open the respective dev server url in the browser.
Now, we can immediately see a couple of things that we need to fix:
- When we type into the input field and click the add button, the task gets added, but the input field is not cleared.
- Click on the add button with an empty input field, and you can add an empty task, which should not happen.
- A good to-have feature would be to add a task by pressing the enter key.
Let's fix these issues one by one while following a Test Driven Development approach.
What is TDD?
You could Google it and find a lot of definitions. Here is a simple one:
TDD is a software development process in which you write tests before you write the actual code.
Why TDD?
- It helps you to think about the problem you are trying to solve before you write the code.
- It helps you to write more confident code.
- It helps you to write more testable code.
- It helps improve accessibility.
- It helps in refactoring.
Now, let's get started with TDD.
Let's fix the issues
Declare the tests first
A good name for the tests would be:
should clear the input field after adding a task
.should not add an empty task
.should add a task by pressing the enter key
.
What's a test.todo
you ask? It's a test that is yet to be implemented. Writing all the tests and implementing them individually is a good practice. (Read more about it here).
If you run the tests now, you will see an output like the one below:
The todo tests are marked as skipped. Let's implement them one by one.
Test: should clear the input field after adding a task
Let's implement the first test. We need to do the following:
- Type into the input field.
- Click on the add button.
- Assert that the input field is cleared.
Make sure to remove the test.todo
and replace it with test
before running the tests and you should see a failing test.
Let's now write the code to make the test pass.
All we did was add setTaskName('')
after adding the task to the list of tasks. Our tests should now pass.
Is there too much test code for a simple implementation? Yes, it might seem useless, but imagine that in the future, we have to refactor the code (any software will always grow unless abandoned) and forget to clear the input field after adding a task. Our tests would fail, and we would know we must fix the code.
Test: should not add an empty task
Let's implement the second test. We need to do the following:
- Click on the add button.
- Assert that the task is not added to the list of tasks.
Make sure to remove the test.todo
and replace it with test
before running the tests, and you should see a failing test.
Let's now write the code to make the test pass.
You can already see that we unintentionally fixed an edge case where the added task name was also trimmed. The power of having to think about the problem before writing the code. We also cleared the initial data for our tasks. Our tests should now pass.
You could also disable the add button if the input field is empty. Disabling buttons is usually considered a bad practice, and we agree. The why is out of the scope of this tutorial.
But I'd suggest reading the article "The problem with disabled buttons and what to do instead" by Adam Silver to learn more about why you should not disable buttons.
Test: should add a task by pressing the enter key
Let's implement the third test. We need to do the following:
- Type into the input field.
- Press the enter key.
- Assert that the task is added to the list of tasks.
Make sure to remove the test.todo
and replace it with test
before running the tests and you should see a failing test.
Let's now write the code to make the test pass.
Our tests should now pass. We could further refactor this inline key-down handler into a separate function. It's pretty simple, and if our tests fail, we know we broke something.
Here's what our final code should look like:
Great, we have now fixed all the issues. Let's rerun our tests and see if everything is working as expected.
Great, all the tests are passing. Now, we can be confident that our Todo app will work as expected, even if we refactor the code in the future. We will do a good amount of refactoring in the next section.
At this point, your code should be a good match to the branch of the repository: 6-test-driven-development