Welcome to the exciting world of Test-Driven Development (TDD)! With TDD, you'll be able to catch bugs early, write cleaner code, and make future updates a breeze. In this blog post, we'll be exploring the use of TDD when developing new APIs using Node.js, the Express framework, and Loadmill for our testing framework.
The TDD Process: A Quick Refresher
Before we dive into the specifics of TDD for API development, let's first review the basic steps of the TDD process:
Write a test: First, you'll write a test that describes the desired behavior of your code. This test should fail initially, since you haven't written the code yet.
Run the test: Next, you'll run the test to confirm that it fails.
Write the code: Then, you'll write the code that is needed to make the test pass.
Run the test again: Finally, you'll re-run the test to ensure that it now passes.
API Development with TDD
Now that we understand the basic TDD process, let's look at how to apply it when developing new APIs. One of the key benefits of TDD is that it helps you design your APIs more effectively. By writing tests first, you can think about how your API should behave and what input and output it should accept and produce. This can help you create a more intuitive and easy-to-use API.
Loadmill: Your Testing Sidekick
To get started with TDD for API development, we'll be using Loadmill as our testing framework. Loadmill is a powerful and easy-to-use platform for testing APIs. It offers a wide range of features, such as support for HTTP/HTTPS requests, flexible test assertions, and integration with popular CI/CD platforms. Best of all, it's free to use for personal projects. Sign up for a free account on their website- https://app.loadmill.com.
Tips for Writing Effective Tests
Once you have Loadmill set up, you can begin writing tests for your API. Here are some tips for writing effective tests:
Focus on testing the behavior of your API, rather than the implementation details. For example, test that your API returns the correct HTTP status code and response body, rather than testing that it uses a specific database library or web framework.
Make your tests as self-contained as possible. Avoid making calls to external services or modifying global state, as this can make your tests harder to debug and maintain.
Write tests for both positive and negative scenarios. This will help you catch more bugs and ensure that your API is robust.
Let's shoot some TDD hoops!
In this example, we'll be using TDD to create an API slam dunk, by creating new players and adding them to an existing basketball team. We'll make sure everything runs smoothly and no bugs are left on the court.
Here, I use the Express.js framework to create a simple web server.
Now let's start TDDing with Loadmill. Our first step is to create a new Test Suite specifically for testing our new player entity. Next, we'll write our first test for the player creation API (step 1 of the TDD process).
In this test, we are utilizing Loadmill to send a POST request to the "/players" endpoint with a request body containing the player's name, jersey number, and position. We then extract the player's ID from the response body and assert that it exists, indicating that a new player has been created. When running this test, it will result in a '404 Not Found' error, as expected, since we haven't implemented this endpoint yet (step 2).
Next, we will implement the API to make this test pass (step 3).
When the API receives a POST request, it creates a player and returns the new player's ID in the response body. Now, if we run the test, it should pass (step 4).
But hold on, we're not done yet! While this is a "happy path" scenario, we can't forget about the not-so-happy scenarios. As we all know, testing for both the good and the bad is crucial for a solid API. Let's say that for the jersey number, we only want to accept non-negative integers, and add a test to ensure that this requirement is met.
Here, I expect that the test will fail when trying to create a player with a negative jersey number (by setting the expected result to ERROR). Now, let’s run the tests and pray for failure haha.
And indeed, our tests failed as a result of a successful response when trying to create players with an invalid jersey number. Time to go back to step 3 and write some code to handle this validation.
And running the test.
There you have it!
Now, let's say we have a team entity in our application and we want to add an API that adds a player to a given team. As you may have already guessed, let's start by adding a failing test.
And then Implementing.
And finally running the test.
Awesome! We've just created a poster flow for creating new players and adding them to a team. And the best part is, we can keep this momentum going by adding more tests and APIs for updating players, kicking them off the team, and more.
In summary, TDD is a powerful technique for developing new APIs. By writing tests first, you can design your API more effectively, catch bugs early, and create a more maintainable codebase. By following the steps of the TDD process and using a good testing framework like Loadmill, you can use TDD to build high-quality APIs that are easy to use and maintain. And the cherry on top, when you finish developing a new feature, the tests are already written (Not to imply writing tests isn’t a blast, of course).
* A big thanks to ChatGPT for helping me write this blog! (and especially the lame puns, that's all on ChatGPT)