Early last year, we embarked on the journey of converting our PHP monolith into many microservices. Our comments system was the first and you can read about it here: Dancing Our Way to Reliability.
Testing is paramount to the stability of any system. We wanted to have high test coverage for these new microservices.
Unlike Chuck, we wrote a lot of unit tests with too many asserts. Then we noticed something interesting: every time we refactored the code, half of the time (on average) was spent on updating these unit tests. How could we be confident that we hadn't introduced any regression bugs if the tests were changing at the same time?
Enter service tests.
Before we dive into the details of why and how we use service tests, it's important to distinguish the differences between the various types of tests. The pyramid below describes the different types of tests.
Source: Newman, Sam. Building Microservices. Sabastopol: O'Reilly, 2015. Print.
On the bottom of the pyramid, we have unit tests that test a single function or method. They are isolated so they are fast, but their scope is narrow. There should be lots of unit tests and they should be run on every save.
In the middle of the pyramid we have service tests that test a single code path at a time, stopping at the boundaries of the service by mocking out any external collaborators like databases and external APIs. You may consider a code path being a particular response/output from the service. Because service tests are slower than unit tests, we are running them manually and on pull requests.
Lastly, we have end-to-end tests which are service tests with no mocking. Real databases and external services are used and their resulting values are validated. End-to-end tests are the slowest of the three.
Why Service Tests?
We refactor our code frequently. It's a worthwhile exercise to pay down technical debt accumulated over time. If we do our jobs right, existing functionality of our services shouldn't change and should work better as a result. We want to have the confidence that we haven't introduced any bugs from the refactor.
Service tests give us the confidence to refactor the internals of the service without having to update any tests, as long as the request and response contracts remain the same. To illustrate visually, let's take a look at a typical n-tier web service. The scope of the service tests is bounded by the orange box.
YOU ARE READING
Journey to the Center of Microservices
Non-FictionWe're trying something new. Well, trying two new things. We're starting to blog about Wattpad's journey into the world of microservices. And we're blogging on our own platform. We're proud of the really hard problems we have to solve every day and w...