Creating a test strategy for asynchronous microservices applications

In the last few months I started a personal study project. The initial objective was to further study the differences in the development and implementation of quality strategies for microservices with synchronous and asynchronous communication. I talked about that in this post: Study project about QA strategy for microservices projects

I have learned a lot in this process, and I want to share some of my experiences through some articles with everyone in the community.

Here is the link for the first article, named โ€œCreating a test strategy for asynchronous microservices applicationsโ€: Creating a test strategy for asynchronous microservices applications | by Fernando Teixeira | assert(QA) | Jan, 2021 | Medium

Any feeback is really welcomed!! :slight_smile:

5 Likes

This is quite good, I only wish I had the discipline to be as thorough in my own personal projects!

1 Like

Interesting reading material.

We currently use (also for performance testing) a correlation-id header, which flows through all the following calls so we continue our API tests fully and check the logs (automated) for the results.
Something alike this: The Value of Correlation IDs | Rapid7 Blog

2 Likes

I remember these correlations IDs, from my last time. For a while I was on a production support team and Iโ€™d spend a lot of my time looking at Application Insights logs in Azure and these Correlation IDs were very useful in figuring out data traversal between different systems and generally in investigations.

1 Like

Looks good, you might want to look into API specifications for async messages. Itโ€™s hard to test an API without a defined interface. Turns out it isnโ€™t a solved problem. So if you look at what openapi doing it also becomes clear the are several types of async messaging interfaces like request-> multiple reply that you might want to consider.

Iโ€™ve also found to my horror recently that contract testing support for async interfaces is in its infancy.

3 Likes

Hi, Fernando! Thanks for a great article and code examples.

Here are my few thoughts on the topic.

  1. Contract tests can help to catch only data format bugs, not functional ones. So contract tests are typically used in conjunction with other types of tests.
  2. In some way in-memory databases can help, but the drawback is that you are using a database that is different from the production one. A more stable way is to use a real database in the docker container via Test Containers.
    In case if your application is Spring Boot - based - it is even better to use testcontainers-spring-boot. This library will start all needed third-party dependencies when the application context is started and then automatically shut it down.
  3. You mentioned unit tests for particular classes and integration tests for checking how service works with database or messaging system. But what about checking the whole service in isolation? As you are using the Spring framework, you can start the whole service locally, dependencies in Docker containers, and all other API communication that is mocked using Wiremock. As a result, you will get almost โ€œproductionโ€ configuration for one service but faster and at the local developerโ€™s machine.
    image
4 Likes

Thanks for sharing your thoughts @al8xr :grin:

In regard to the second point, this is an interesting alternative. I have already used Test containers just with a few simple examples. I would like in the future to investigate how reliable are those in-memory databases, in comparison to other strategies that use a real database setup, like test containers or even a docker-compose file. Also, comparing some trade-offs, ease to set up, execution time, reliability, etc.

And regarding the third point, the Spring-Boot framework helped me considerably to create something very similar to what you described. The mechanism to start just a specific service from the project, helps considerably to better validate them having a good execution time. The only difference is that I also used an in-memory Kafka queue, which probably goes to the same topic that I mentioned above about the trade-offs of having a real setup or just use some in-memory components options.
I tried to do once a similar setup but using the .NetCore framework, and I had much more difficulty, since it didnโ€™t have something similar to the Spring framework to start some isolated and specific services :disappointed_relieved:

3 Likes