Microservices are distributed applications deployed in different environments and could be developed in different programming languages having different databases with too many internal and external communications. A microservice architecture is dependent on multiple interdependent applications for its end-to-end functionalities. This complex microservices architecture requires a systematic testing strategy to ensure end-to-end (E2E) testing for any given use case. In this blog, we will discuss some of the most adopted automation testing strategies for microservices and to do that we will use the testing triangle approach.
It’s a modern way of testing microservices with a bottom-up approach, which is also part of the “Shift-left” testing methodology (The “shift-left” testing method pushes testing towards the early stages of software development. By testing early and often, you can reduce the number of bugs and increase the code quality.). The goal of having multiple stacked layers of the following test pyramid for microservices, is to identify different types of issues at the beginning of testing levels. So, in the end, you will have very few production issues. Each type of testing focuses on a different layer of the overall software system and verifies expected results. For a distributed microservices app, the tests can be organized into the following layers using a bottom-up approach:
Testing triangle is based on these five principles:
It's the starting point and level 1 white box testing in the bottom-up approach. Furthermore, it tests a small unit of source code functionality of microservices and verifies the behavior of source code methods or functions inside a microservice by stubbing and mocking dependent modules and test data. Application developers write unit test cases for a small unit of code (independent functions/methods) using different test data and analyzing expected output independently without impacting other parts of the code. It's a vital part of the “shift-left” testing approach, where issues are identified in the starting phase at method level of microservices. This testing should be done thoroughly with code coverage of more than ~90%. It will reduce the chances of potential bugs in the later phases.
It’s the level 2 testing of the Testing Triangle that follows unit testing. This testing aims to test entire microservices functionalities and APIs independently in isolation for individual microservice. By writing component tests for highly granular microservices layer, the API behavior is driven through tests from the client or consumer perspective. Component tests will test the interaction between microservice APIs/services with the database, messaging queues, external, and third-party outbound services all as one unit.
It tests a small part of the entire system. In component testing, dependent microservices and database responses are mocked or stubbed. In this testing approach, all microservices APIs are tested with multiple sets of test data.
It’s the level 3 testing approach that verifies agreed contracts between different domain-driven microservices. There are contracts defined before development of microservices in the API/interface, designing what should be the response for the given client request or query. If any changes happen, then the contract has to be revisited and revised. For example, if any new feature changes are deployed, then they must be exposed with a separate version /v2 API request, and we need to make sure that the older /v1 version still supports client requests for backward compatibility.
It tests a small part of the integration, like:
It’s level 4 testing which verifies end-to-end functionality. It is the next level of contract testing, where integration testing is used to test and verify an entire functionality by testing all related microservices.
According to Martin Fowler, an integration test exercises communication paths through the subsystem to check for any incorrect assumptions, each module has about how to interact with its peers.
It tests a bigger part of the system, mostly the microservices exposing their services with API. For example:
It's the final and the level 5 testing approach in the Testing Triangle and it is an end-to-end usability black box testing. It verifies that the entire system as a whole meets business functional goals from a user or a customer or a client prospective. E2E testing is performed on the external front-end (user interface (UI)) or API client calls with the help of the REST clients. It’s performed on different distributed microservices and SPA (Single Page Apps)/MFE (Micro Front ends) applications. It covers testing of UI, backend microservices, databases and their internal/external components.
Many organizations have already adopted digital transformation which uses microservice architecture. IT organizations find it challenging to test microservices applications because of its distributed nature. We will discuss the important challenges and solutions offered by some of the industry experts:
Testing triangle provides great testing techniques to solve challenges associated with microservices. We need to choose these systematic testing techniques with a perspective on lower complexity, faster testing, time to market, testing cost, and risk mitigation before releasing to production. This testing strategy is required for microservices to avoid real production issues. This ensures that test cases should cover end-to-end functional and non-functional E2E testing for UI, backend, databases and different PROD and Non-PROD staging environments for reliable product releases.
We have seen microservices introduce many testing challenges which can be solved with step by step (down to top) approach provided by testing triangle techniques.
It’s a modern cloud native testing strategy to test microservices on cloud. It finds and fixes maximum bugs during testing phase until it reaches the highest level (topmost level in the triangle), which is E2E testing.
Tips: Many IT organizations have started following “Shift-left” culture and have started using testing culture especially in situations where identifying and fixing bugs early is important.