A lesson on how to test microservices locally
In the early days of microservices, a developer wrote 20 lines of code, and then registered a subdomain to an IP address and port. Ten years later, that process is even easier. With the help of cloud abstraction and serverless, developers can write the code, publish it to a version control environment, and connect a system to that code — server management, scaling and other back-end processes are all handled in the cloud.
But how do you test these cloud-hosted microservices-based applications locally? You could test on a local machine, or at least a local container, before you push the code into a test environment. However, a typical microservices-based application calls as many as 60 separate services. To test these complex applications locally, you’ll need to assemble each individual service, and probably the underlying databases, on the local machine. Testing microservices locally often involves running a half-dozen terminal sessions on one machine.
A better option is to separate and isolate services, which is always a good idea when performing either unit testing or integration testing on complex application architectures. First, we’ll review the process of testing microservices locally, including unit and integration testing. Then, we’ll take a look at some effective techniques for service isolation, such as service virtualization and private cloud test clusters.
Using a testing framework, like JUnit for Java code, it’s possible to test pieces of a microservices-based application as individual units. When those small, testable collections of methods run into a dependency, such as a database connection, you can use dependency injection to create the stubs, mocks and fakes needed to accurately test the service. When it comes to simple unit tests, there are easy patterns to learn, such as the Arrange, Act and Assert pattern. Arrange, Act and Assert calls for a setup, action and then validation of a result.
Testing a service while it runs, integrated with other components, is a different matter. Integration testing is a little trickier than unit testing. Instead of creating unit-level mocks, you design tests to mimic the numerous integrations involved, in a realistic way.
Service virtualization is a way to record the response of a service to a certain call, and then play the sequence back on-demand. This approach provides a lightweight, predictable service mock you can test against as needed. And, you likely will mock or stub out the databases and other external components they interact with.
When you can’t isolate microservices
Service virtualization, changing dependencies and test flags can be difficult to set up. You need expertise in that kind of coding. And architecture groups might want to dictate the “right” way to stand up test services, or prevent the development teams from adopting new virtualization tools.
If you can’t directly change the code to run microservices tests locally as described above, try creating a new environment that contains the entire collection of services you want to test. To do that, implement a mechanism that scans for and identifies every dependency. Pact.io is an open source contract test tool which can do this; Microservice Graph Explorer is another.
Once you’ve identified the services and their dependencies to test, create containers that can run the service, and connect them all to the same test database. Then, create a test cluster — use a public or private cloud — that contains the actual services and mocked data. You might be tempted to perform these tests locally on a desktop, since you won’t need permissions or licenses to do so. However, simulating multiple services on a desktop, coupled with the overhead of a cluster manager, leads to performance problems.
This technique of creating all the dependencies for a service and mocking what is appropriate is essentially an infrastructure project. It will be time-consuming and a little expensive. However, once it’s created, you’ll have an opportunity to truly test microservices in isolation.