{"id":14357,"date":"2019-12-23T18:25:36","date_gmt":"2019-12-23T12:55:36","guid":{"rendered":"https:\/\/cigniti.com\/blog\/?p=14357"},"modified":"2022-07-19T18:06:43","modified_gmt":"2022-07-19T12:36:43","slug":"microservices-architecture-testing-strategies","status":"publish","type":"post","link":"https:\/\/www.cigniti.com\/blog\/microservices-architecture-testing-strategies\/","title":{"rendered":"Best testing strategies in a Microservice architecture"},"content":{"rendered":"

Today, there<\/span>\u00a0is<\/span>\u00a0no dearth of\u00a0<\/span>information\u00a0<\/span>related to\u00a0<\/span>microservices on the web<\/span>\u00a0about\u00a0<\/span>what\u00a0<\/span>they<\/span>\u00a0are and how organisations\u00a0<\/span>are\u00a0<\/span>transforming their development architecture.<\/span>\u00a0However, there are very\u00a0<\/span>few articles that\u00a0<\/span>talk<\/span>\u00a0about\u00a0<\/span>the test strategies<\/span>\u00a0<\/span>that must\u00a0<\/span>be followed while testing<\/span>\u00a0microservice architectural solutions and applications.<\/span>\u00a0This blog aims to help you provide the information.<\/span>\u00a0<\/span><\/p>\n

Before\u00a0<\/span>I<\/span>\u00a0continue to the Strategy, Test Areas, Test Types,\u00a0<\/span>etc.<\/span>,\u00a0<\/span>let<\/span>\u00a0u<\/span>s<\/span>\u00a0understand some of the definitions of microservices.<\/span>\u00a0<\/span><\/p>\n

A microservice is a software development technique\u2014a variant of the\u202f<\/span><\/i>service<\/span><\/i><\/b>–<\/span><\/i>o<\/span><\/i>riented\u202f<\/span><\/i>architecture<\/span><\/i><\/b>\u202f(SOA)\u202f<\/span><\/i>architectural<\/span><\/i><\/b>\u202fstyle that structures an application as a collection of loosely<\/span><\/i>–<\/span><\/i>coupled\u202f<\/span><\/i>services<\/span><\/i><\/b>. In a\u202f<\/span><\/i>microservices architecture<\/span><\/i><\/b>,\u202f<\/span><\/i>services<\/span><\/i><\/b>\u00a0<\/span><\/i><\/b>are fine-grained and the protocols are lightweight.<\/span><\/i>\u00a0<\/span><\/p>\n

A microservice architecture builds software as suites of collaborating services. Microservices are often integrated using REST over HTTP.<\/span><\/i>\u00a0<\/span><\/i>They<\/span><\/i>\u00a0connect<\/span><\/i>\u00a0with each other over networks\u00a0<\/span><\/i>and make use of \u201cexternal\u201d datastores<\/span><\/i>.<\/span><\/i>\u00a0<\/span><\/p>\n

Microservice architecture, or simply microservices, is a distinctive method of developing software systems that tr<\/span><\/i>y<\/span><\/i>\u00a0to focus on building single-function or single<\/span><\/i>–<\/span><\/i>purpose modules with well-defined interfaces and operations.<\/span><\/i>\u00a0<\/span><\/i>This trend has grown popular in recent years as enterprises look to become more Agile and move towards a DevOps and continuous testing<\/span><\/i>\u00a0approach<\/span><\/i>. Microservices can help create scalable, testable software that can be delivered very often; some of them as frequent as weekly and daily.<\/span><\/i>\u00a0<\/span><\/p>\n

Microservices architecture allows admins or users to load just the services that are required, which improves deploy times, especially when packaged in containers.<\/span><\/i>\u00a0<\/span><\/p>\n

Microservices provide changes only when and where they<\/span><\/i>\u00a0a<\/span><\/i>re needed. With a microservices architecture, the application monitors each functional component.<\/span><\/i>\u00a0<\/span><\/p>\n

Why do\u00a0<\/span><\/b>you<\/span><\/b>\u00a0need a special strategy to test microservices?<\/span><\/b>\u00a0<\/span><\/p>\n

You<\/span>\u00a0need a different strategy to test\u00a0<\/span>microservice<\/span>s as t<\/span>h<\/span>ey<\/span>\u00a0follow a different architecture\u00a0<\/span>and\u00a0<\/span>ha<\/span>ve<\/span>\u00a0<\/span>a\u00a0<\/span>lot of integrations with other microservices within one\u2019s organisation\u00a0<\/span>as well as<\/span>\u00a0from\u00a0<\/span>the\u00a0<\/span>outside world (3<\/span>rd<\/span>\u00a0party integrations)<\/span>.<\/span>\u00a0<\/span>Additionally, these\u00a0<\/span>require\u00a0<\/span>a\u00a0<\/span>high amount of collaboration among different teams\/squads developing individual microservices<\/span>. Moreover, they<\/span>\u00a0<\/span>are single purpose services<\/span>\u00a0and<\/span>\u00a0are deployed independently\u00a0<\/span>&<\/span>\u00a0regularly.<\/span>\u00a0<\/span><\/p>\n

The Strategies<\/span><\/b>\u00a0<\/span><\/p>\n

Before\u00a0<\/span>I<\/span>\u00a0discuss\u00a0<\/span>the various\u00a0<\/span>strateg<\/span>ies, let<\/span>\u00a0us<\/span>\u00a0take a look at a self-explanatory diagram to\u00a0<\/span>understand the composition of microservices.<\/span>\u00a0<\/span><\/p>\n

\"\"<\/p>\n

D<\/span>ifferent types of testing\u00a0<\/span>need\u00a0<\/span>to be performed at different layers of microservices<\/span>.<\/span>\u00a0<\/span>Let<\/span>\u00a0u<\/span>s\u00a0<\/span>look<\/span>\u00a0at them using\u00a0<\/span>an illustration\u00a0<\/span>of<\/span>\u00a0three microservices collaborating\/working closely.\u00a0<\/span>A<\/span>ssume<\/span>\u00a0Microservices A, B<\/span>,<\/span>\u00a0and C are working together along with many other Microservices (not shown in picture).<\/span>\u00a0<\/span>Th<\/span>e<\/span>\u00a0following diagram illustrates all testing types and their boundaries by taking one microserv<\/span>ice (Microservice B) as an example.<\/span>\u00a0<\/span><\/p>\n

\"\"<\/p>\n

Unit Testing<\/span><\/b>\u00a0<\/span><\/p>\n

A unit test exercises the smallest piece of testable software in the application to determine whether it behaves as expected.<\/span><\/i>\u00a0<\/span><\/p>\n

Unit tests are typically written at the class level or around a small group of related classes. The smaller the unit under test<\/span>,<\/span>\u00a0the easier it is to express the behaviour using a unit test<\/span>.<\/span>\u00a0<\/span>With unit testing, you see an important distinction based on whether or not the unit under test is isolated from its collaborators.<\/span>\u00a0<\/span><\/p>\n

Referring to the above images, unit tests are written for the internal\u00a0<\/span>modules<\/span>\u00a0of a given microservice<\/span>\u00a0(for each internal module of a microservice)<\/span>.\u00a0<\/span>Test doubles, stubs<\/span>,<\/span>\u00a0and mocking can<\/span>\u00a0be incorporated\u00a0<\/span>to replace any\u00a0<\/span>dependencies.<\/span>\u00a0<\/span>Usually<\/span>,<\/span>\u00a0your developers write Unit Tests and\u00a0<\/span>as a QA engineer\u00a0<\/span>you may want to make sure they do write some unit tests as part of their code commits.<\/span>\u00a0<\/span><\/p>\n

Integration<\/span><\/b>\u00a0Testing<\/span><\/b>\u00a0<\/span><\/p>\n

Unit testing\u00a0<\/span>alone does<\/span>\u00a0no<\/span>t provide guarantee<\/span>\u00a0about the behaviour of the system<\/span>.\u00a0<\/span>You<\/span>\u00a0must address the coverage of the internal modules when they work together to form a complete\u00a0<\/span>Micro<\/span>service.\u00a0<\/span>You<\/span>\u00a0must also address the interactions the modules make with remote dependencies.<\/span>\u00a0<\/span><\/p>\n

An integration test verifies the communication paths and interactions between the modules<\/span><\/i>\u00a0and between their dependencies.<\/span><\/i>\u00a0<\/span><\/p>\n

Integration tests collect modules together and test them as a subsystem in order to verify that they collaborate as intended to achieve some larger piece of behaviour.\u00a0<\/span>Example of integration tests between modules are tests verifying the communication between<\/span>\u00a0Repositories & Service Layer,\u00a0<\/span>Service Layer\u00a0<\/span>&<\/span>\u00a0Resources<\/span>,<\/span>\u00a0etc.<\/span>\u00a0<\/span>Integration test<\/span>\u00a0examples for external dependencies include\u00a0<\/span>the tests between\u00a0<\/span>data stores, caches<\/span>,<\/span>\u00a0and other microservices.<\/span>\u00a0<\/span><\/p>\n

You often end up writing an extended version of your unit tests on the internal modules and start calling them as Integration Tests. Thus<\/span>,<\/span>\u00a0it is a good idea to delegate the job of writing automated integration tests to your developers because it is easy for them to use the existing unit test frameworks to extend for Integration Tests. It needs them using the real instances of the internal modules involved (Ex: API Resources, Service Layer, DBs, and Message Queues<\/span>,<\/span>\u00a0etc.).<\/span>\u00a0<\/span>Testers can choose to do this activity provided the infrastructure team is ready to give you\u00a0<\/span>an<\/span>\u00a0integration environment with all the real dependencies deployed.<\/span>\u00a0<\/span><\/p>\n

In both cases, write just a handful of test cases, do not automate an exhaustive list as the complete functional testing will be covered by other testing types (Component Tests). These tests should just act like a health check<\/span>\u00a0activity<\/span>\u00a0between the integration layers with a small test suite size.<\/span>\u00a0<\/span><\/p>\n

Component Testing<\/span><\/b>\u00a0<\/span><\/p>\n

With Unit and Integration Testing,\u00a0<\/span>you<\/span>\u00a0can gain confidence on the quality of the internal modules that make up the microservice, but\u00a0<\/span>you<\/span>\u00a0cannot guarantee that the microservice works together as a whole to satisfy the business requirements.\u00a0<\/span>You<\/span>\u00a0must end-to-end<\/span>\u00a0test\u00a0<\/span>the integrated microservice by isolating it from external\u00a0<\/span>dependencies<\/span>\u00a0and other collaborating microservices.<\/span>\u00a0<\/span><\/p>\n

A component test verifies the end-to-end functionality of<\/span><\/i>\u00a0the<\/span><\/i>\u00a0given microservice in isolation by replacing its dependencies by test doubles and\/or mock services.<\/span><\/i>\u00a0<\/span><\/p>\n

In a microservice architecture, the components are the services themselves. By writing tests at this granularity, the contract of the API is driven through tests from the perspective of a consumer. Isolation of the service is achieved by replacing external collaborators with test doubles and by using internal API endpoints to probe or configure the service.<\/span>\u00a0<\/span><\/p>\n

Referring to the above microservice diagram, component tests focus\u00a0<\/span>on<\/span>\u00a0one microservice at a time. For example<\/span>,<\/span>\u00a0testing Microservice A in isolation<\/span>,<\/span>\u00a0and then B<\/span>,<\/span>\u00a0and then C<\/span>,<\/span>\u00a0and so on.\u00a0<\/span>If Microservice A closely collaborate<\/span>s<\/span>\u00a0with Microservice B and you want to test Microservice A in isolation<\/span>,<\/span>\u00a0then you would replace Micr<\/span>oservice B with a mock service<\/span>, i<\/span>ntegrate the mock with Microservice A<\/span>,<\/span>\u00a0and<\/span>\u00a0then<\/span>\u00a0test it end-to-end.<\/span>\u00a0<\/span><\/p>\n

Testing such components in isolation provides a number of benefits<\/span>:<\/span>\u00a0<\/span><\/p>\n