One of the complexities that arise in a microservices architecture based application is about testing different micro-services. For each micro-service, one can write unit test cases by mocking external dependencies and can concentrate more on a logical piece of work.
But when it comes to looking beyond the regular unit testing, then the need arises for special test cases like integration test cases and end-to-end test cases. Integration test cases cover the dependency management aspect of microservices with external entities like databases, external services, etc., whereas end-to-end test cases are more of testing the application as a whole from the customer perspective.
A testing pyramid has three layers from bottom to top, i.e. Unit Testing, Integration Testing, System Testing (end-to-end).
Basically, as we move up from the bottom layer to the top layer, the number of test cases decreases, interaction among test cases increases, and, last but not the least, the perspective changes from code-centric to customer-centric.
This is the base layer of the pyramid where most the development takes place. These test cases are written using frameworks like JUnit, and mocking frameworks like Mockito, PowerMockito, etc. The essential purpose of these test cases is to test the behavior of one's service and isolating it from external dependencies like external services and databases. This type of testing approach ensures the code works at the granular level.
This is the middle layer of the pyramid and, as the name suggests, it is more about integrating different microservices to validate a business flow. It involves interaction with external services and databases which were missing at the base layer. This is the layer where we can bring in more automation to glue together different microservices and make sure that a business flow is working fine.
System Tests /End-to-End Testing
This is the top layer of the pyramid and is more UI concentric. The purpose of this testing is to verify the entire application is working as a whole or not. The testing scenarios will include all service and database interactions. Only the most critical test scenarios are covered here, especially from the perspective of the customer's daily interaction with the application.
Things to Look at in Each of the Pyramid's Layers Are:
By this I mean, how to decide which tools and frameworks to leverage for different testing approaches.
For example, we can have a Mockito framework for the unit testing of microservices.
For integration testing, we can have a framework which invokes endpoints of each microservice to ensure their availability and verify their HTTP return code.
Similarly, with an end-to-end layer of testing, there are automated Cucumber/Capybara scripts available that can perform smoke testing.
So, when should you decide upon whether testing will be manual, automated, part of release train etc?
The unit test cases can be programmed to execute automatically during a pull request. And one can merge a PR, only if that PR satisfies unit test coverage and other sonar metrics successfully.