In the first part of this blog, I gave you an overview of how the microservices architecture differs from the classic monolithic software architecture and we explored why microservices are so hard to test using traditional testing methodologies. I gave 5 tips for how you might approach your test planning and briefly touched on serverless architectures. In this second blog, we will look at how you can leverage test automation in order to help you with testing your microservice-based application. We will also see how Artificial Intelligence and Machine Learning can further improve this approach before touching on serverless architectures.
How to add automation to your microservices testing
I'll start with a brief reminder of the 5 tips I gave for testing microservices:
- Treat each service as a software module.
- Work out the essential links in your architecture and seek to test those.
- Don't try to assemble the entire microservice environment in a small test setup
- Try to test across different setups.
- Make good use of Canary testing for new code.
Taking each of these pieces of advice in turn, let’s see if and how we can apply test automation to help us.
Test each service individually
Clearly, test automation is a powerful tool for testing discrete microservices. It is extremely easy to create a simple test harness that repeatedly calls the service and compares a known set of inputs against an expected output. But in and of itself this isn’t going to get you very far with your testing. It will, however, free up your test team to concentrate on more complex testing.
Test the different functional pieces of your application
Having identified the key functional elements in your application you should seek to test these in much the way you would traditionally do integration testing. Here the benefits of test automation are clear. You can easily create test scripts that are run each time one of the microservices is updated. By comparing the outputs of the new code with previous outputs, you can quickly establish if anything has changed. Of course, you need to know what the intended output is meant to be. It may well be that the change is actually one you wanted (e.g. you might have updated your payments system to automatically include sales taxes, thereby changing all the output values).
Don’t try to test in a small setup
There’s a tendency among some managers to starve their testing team of resources. But with microservices-based applications this is counterproductive. Rather than trying to create small local staging environments to test your code in, you should look to leverage cloud-based testing. Here you can dynamically allocate resources as your tests need them, freeing them up when your tests have completed. As such, test automation won’t directly help you here. However, you should make sure that you follow this advice in any automated testing you do.
Try to test across different setups
One of the most important bits of advice I gave was to use multiple environments to test your code. In a way, you could think of this as being similar to cross-browser testing for web applications. The idea is to expose your code to any minor variations in things like library versions, underlying hardware, etc. that might impact it when you deploy to production. One way to do this might be to create your staging environments on the fly. Using something like Kubernetes, it’s possible to create a test environment, populate it with data from a known source, load your code and then run your tests. The beauty of this is that because the environment is recreated each time you are automatically exposed to any differences that might exist. Of course, the flip side is that you may find it harder to diagnose the underlying cause of any bugs you find.
Use Canary testing as much as possible
Canary testing is an approach where a small set of users are exposed to changes in the code and you compare their experience with the experiences of those users still running the old code. This approach is particularly useful for testing microservices. The great thing here is that you can use monitoring to assess the impact of the change. Look at things like error rates, service load, responsiveness, and similar metrics can tell you whether your new code has had a negative impact. By adopting a strategy where one service instance at a time is updated, you can easily and automatically do canary testing.
AI or Artificial Intelligence can be used to completely automate canary testing of your microservices application. AI approaches such as deep learning can be used to identify changes and issues that are triggered by the new code. A small number of users are moved over to the new system and the AI compares their experience with that of the existing users. Because this can be done automatically, you can replace the human in the loop.
Here at Functionize, we are partnering with Google cloud to develop this new approach. Our approach uses machine learning for advanced anomaly detection. By comparing the different metrics such as error rates and system load, the system identifies any anomalies that are affecting the users running the new code. These can then be automatically reported back to the developers.
Putting all the pieces together
So how can you combine all these pieces and use test automation to improve your approach to testing microservices? The first thing is to make test automation central to your development process. By this, I mean always start from the idea that you want to automate your testing as far as possible. So begin by defining all your APIs according to a standard specification such as Open API or API Blueprint. This will allow you to integrate mock API servers and endpoints into all your tests.
Next look to use automatic creation of staging environments for testing discrete parts of your application. If you are clever you should be able to take advantage of things like AWS spot pricing for this. While developing your application you will need to integrate this with your mock APIs. After your application is first released you should also start to pull in real data for your testing. But obviously, make sure you aren’t breaching any data protection laws like the EU’s new General Data Protection Regulations (GDPR)!
Then look at how you can automate the process of canary testing. When new code is ready to be shipped your system should be designed to ensure that only a limited subset of users is moved onto the new code at a time. It’s important that these users are a representative mix and are sufficiently active to give you valid results quickly. As discussed above, you can then use machine learning to automate the process of monitoring the performance of the new code and to identify any bugs.
Finally, you should consider how to automatically monitor the ongoing performance of your application. Often with microservices-based applications, you will identify as many bugs in production as you will during the testing phase. Having systems in place to spot these bugs before they cause problems is essential. Try to code defensively and make sure your code is well instrumented (although be cognizant of the risk that if you over-instrument it you will suffer a drop in performance.
Microservices and containerization were buzzwords a couple of years back. But now there’s a new kid on the block. Serverless Architectures can be seen as the logical progression of containerization. Here you build your application backend from discrete functions that are provided by a Function as a Service (FaaS) vendor – think Amazon Lambda or Google App Engine. In the serverless model, you simply combine existing functions to create your backend. For instance, your accounting app may call a 3rd party function that provides AI parsing of scans of invoices or receipts.
From a testing viewpoint, this means you can be sure the underlying service works (as we have seen, Amazon goes through a very careful process before they allow a new service to be rolled out). However, you must be very clear about the assumptions that were made when the functions you are using were defined. You also need to ensure your tests make realistic demands on the functions you are using. Often this will require using copies of real user data (with all the data protection ramifications that go with that). Also, because you are getting a pre-made function, you are often more limited in the monitoring that is available to you. This can make Canary testing a little more challenging.
In these blogs, I have shown you why the traditional approach to testing isn’t sufficient in a world of microservices-based applications. We looked at 5 tips on how to test such applications and now we have seen how automation and AI can be used to achieve these.