DEV Community

Yan Cui
Yan Cui

Posted on • Originally published at theburningmonk.com on

How to apply the TDD mindset to serverless

Testing is an integral part of software development. Your tests are a living documentation of your system. They inform others how to use your system, but they are so much more than that.

One of the most misunderstood parts of Test-Driven Development (TDD) is the “Driven” part of the name.

It’s not just about “writing tests before you write the code”. If your tests do not inform and drive your API design, then you’re not really doing TDD.

When I say “API”, I mean the general meaning of the term, not the API spec for HTTP APIs, although they are part of it. In the context of a serverless application, you have to cover multiple APIs with your tests.

  • For an HTTP API, there are the API contracts you agree with the caller.
  • For an event-driven architecture, there are event contracts that everyone agrees on.
  • For the Lambda function, there is the handler function’s signature (its input and output types). In most cases, we don’t have control over these, as the function’s event source dictates them.
  • The code modules that are executed when a Lambda function is invoked.

Different types of tests [1] can drive the design of the different APIs above.

For example, end-to-end tests exercise the system from the outside. An e2e test will exercise an HTTP API by calling its HTTP endpoints as a client would. They should tell you if your API is difficult to use and drive you towards a better API design.

Similarly, unit tests exercise the business logic encapsulated in the code modules. They should tell you if you have the right abstraction and modularity in place and drive you towards a better code organization.

To apply the TDD mindset to serverless development:

  1. Write e2e tests for your API before you even think about the Lambda functions behind those API endpoints.
  2. Use the tests to identify problems with the API design. Is data missing from the API responses? Are we asking the caller to make multiple calls when we can do everything they want in one?
  3. Iterate and improve.
  4. Once the API spec is set, you can map API endpoints to Lambda function(s).
  5. Now, it’s time to implement the Lambda function handlers.
  6. Use unit tests to test your domain logic and use them to drive your API design.

Does this look similar to what you’d do if you were building serverful applications running on containers or EC2?

It should! The environment our code runs in should not influence how we can use tests to drive our design.

But with serverless, we want to leverage the cloud to its full potential and delegate the heavy lifting to the cloud provider. It changes what and how much code we have to write and maintain. So, it changes how and what we need to test.

For example, I’d delegate authentication and authorization to API Gateway. So, there is no authentication-related code in my Lambda function, and there’s no need for me to write unit tests for it. Instead, authentication is checked as part of my e2e tests. I might even have an e2e test to make sure that unauthorized requests are rejected by API Gateway.

Similarly, most of my Lambda functions are simple and do not have complex business logic. So, there is a low return on investment (ROI) from unit tests. Instead, I focus on testing the integration with the external dependencies (such as DynamoDB tables) with “remocal tests”.

I wrote about my testing strategy for serverless applications [2] previously. If you want to learn more about testing serverless applications, please read that.

But remember, tests are not just for catching bugs and preventing regressions. They are also living documentation for your system and a way to drive its design.

Links

[1] What is the Test Honeycomb? (and why you should care)

[2] My testing strategy for serverless applications

The post How to apply the TDD mindset to serverless appeared first on theburningmonk.com.

Top comments (0)