Like any other application, continuous testing of serverless applications is essential to ensure the quality of the product. Testing a serverless application is not drastically different from testing a regular application. In traditional application testing, we configure an environment similar to the production environment in the development area and test it. But when dealing with the serverless providers, you cannot simulate the exact production environment. In this article, let’s talk about testing serverless applications and the alterations we should make to the normal testing process.
Serverless Applications: Unit Testing
In unit testing, we test each unit of code individually without involving other third-party code and services. In the serverless context, unit testing is pretty much the same as in traditional application testing. So, you can use the same test frameworks like Jasmine, Mocha, Jest, etc., when testing serverless applications. In the serverless concept, most of the complexities are around serverless functions and their integrations. So, the effort of the unit testing for a serverless application is comparatively low.
Serverless Applications: Integration Testing
The purpose of integration testing is to test interactions across application components that are already unit tested. In serverless, we test our code against external services which our application relies on, such as Amazon SQS, Amazon RDS or Amazon S3. Since you’ll be interacting with the actual infrastructure components of your application, you’ll need to make sure you stage your application during development/testing. Therefore, you assume the behaviour of the external services with the same assumptions you have made in writing the code.
Based on those assumptions, you can mock or stub those external services during the integration testing. So if the tests fail, you can verify the accuracy of your assumptions you have made while coding. Likewise, when running integration tests with serverless functions, you’ll also need to have some event mocks prepared to invoke the functions locally.
But even though these mocked and stubbed services and events work for negative testing, you must always use real services for at least the happy path, since testing in the cloud itself is the only way to ensure that everything is configured correctly.
Serverless Applications: Local Testing
In serverless architecture, the cloud provider manages the infrastructure. Therefore, running your application locally is a tricky business.
In serverless applications when running tests locally, instead of native compilers and interpreters you have to replicate your entire execution environment with all the dependencies and libraries which will be used on the actual runtime in your cloud platform to get accurate test results.
AWS console itself has a feature to test Lambda functions. But when uploading large deployment packages and when there’s a requirement to add 3rd party dependencies in your application, AWS console test feature may not be the best option. If you find such difficulties you can use Sigma IDE which utilizes its test framework by managing a test environment on AWS, which allows developers to execute test events along with debugging.
SAM Local is a tool provided by AWS to its customers to test their serverless application locally before deploying it to the cloud. This way, you can verify the intended behaviour of your application even before deploying. And SAM Local will allow you to invoke your Lambda functions locally with debugging capability. Therefore, you can identify and fix issues as you would do in a “serverful” application.
Serverless Applications: Acceptance Testing
Since a serverless application is a combination of many cloud services, you may accidentally skip or misconfigure settings of some. For example, let’s say you have created a Lambda function with a basic execution role. Your use case is to fetch an object from an S3 bucket when the lambda is triggered by an API Gateway HTTP request. But you forgot to give necessary IAM permissions to access the relevant S3 bucket. So, when invoked in production, the lambda won’t be able to communicate with that S3 bucket.
Even if you add necessary permissions in the IAM policy, your lambda may time out even before reaching the S3 bucket if you’ve mistakenly set a shorter execution time for the lambda. Unit, Component or Integrations tests may not cover these configuration errors. To avoid these misconfigurations you might need to run your functions after deployment, to ensure they are working properly. It is the only way to test against the various limitations set by cloud service providers. In the above use case, you can call the API endpoint using an HTTP client like Postman and validate the response to check whether there are configuration issues.
Serverless Applications: UI Testing
If you are developing a website or a mobile app, UI testing is one of the main concerns. Like any other application, you can test UIs of your serverless application by setting up emulators or using automation tools like TestCafe, Selenium, and Cucumber. Amazon itself provides AWS Device Farm to test your Android and iOS mobile and web apps, across multiple browsers with real devices hosted in the cloud or run automated scripts written in frameworks like Appium and Espresso.
Error logging is as important as testing serverless applications. So, when it comes to troubleshooting, you would need a properly configured error log with all the traces. Many cloud providers provide error logging services which allow you to check what’s going on in your serverless application.
AWS CloudWatch is the monitoring and observability service provided by AWS for its cloud resources. Similarly, Azure provides Azure Monitor and GCP provides Stackdriver. But since the infrastructure control is mostly upheld by the cloud providers, you have to rely on what your cloud provider allows you to see. So you won’t be able to access the underlying hardware resources to troubleshoot errors which are specific to your application. And also, serverless functions are alive only during the code execution time. So, their runtime state will be lost after the execution. Therefore, it’s really important to use real-time testing tools when testing serverless applications.
As discussed above, there are a few differences in the testing process when it comes to a serverless application. Some tasks may need more effort and attention and some may need less, compared to a traditional application. A proper understanding of serverless concepts and the correct combination of tools and technical competencies will surely accelerate your process of developing and testing better serverless applications.