Introduction to Serverless Testing: Using Cucumber with AWS Lambda

In the rapidly evolving landscape of software development, serverless computing has emerged as a powerful paradigm. AWS Lambda, a leading serverless platform, allows developers to execute code in response to events without managing servers. While the benefits of serverless architecture are compelling, it introduces new challenges in testing. This article explores how to effectively test AWS Lambda functions using Cucumber, a popular Behavior-Driven Development (BDD) tool.

What is AWS Lambda?

AWS Lambda is a compute service that lets you run code without provisioning or managing servers. Lambda executes your code only when needed and scales automatically, from a few requests per day to thousands per second. You pay only for the compute time you consume.

Why Use Cucumber for Testing?

Cucumber facilitates BDD by allowing you to write test cases in a natural language that stakeholders can understand. It uses Gherkin syntax, which describes features and scenarios in plain English, making it easier to collaborate with non-technical team members.

Setting Up Your Environment

Before diving into testing, ensure you have the following tools installed:

  • Node.js and npm: For managing packages.
  • AWS CLI: To interact with AWS services.
  • Serverless Framework: To simplify the deployment of Lambda functions.
  • Cucumber: For BDD.

You can install these tools using the following commands:

# Install Node.js and npm
sudo apt-get install nodejs npm

# Install AWS CLI
sudo apt-get install awscli

# Install Serverless Framework
npm install -g serverless

# Install Cucumber
npm install --save-dev cucumber

Writing Your First Lambda Function

Let’s start by writing a simple Lambda function. Create a new directory for your project and initialize a new Serverless service:

mkdir serverless-cucumber-example
cd serverless-cucumber-example
serverless create --template aws-nodejs --path my-service
cd my-service
npm init -y

In the handler.js file, write a simple function that returns a greeting message:

'use strict';

module.exports.hello = async (event) => {
  return {
    statusCode: 200,
    body: JSON.stringify({
      message: 'Hello, World!',
      input: event,
    }),
  };
};

Deploy the function using the Serverless Framework:

serverless deploy

Writing Cucumber Tests

Next, create a features directory and a step_definitions directory within it. In the features directory, create a file named hello.feature:

Feature: Hello Lambda Function

  Scenario: Getting a greeting message
    Given I have a deployed Lambda function
    When I invoke the Lambda function
    Then I should receive a greeting message

In the step_definitions directory, create a file named helloSteps.js:

const { Given, When, Then } = require('cucumber');
const AWS = require('aws-sdk');
const lambda = new AWS.Lambda();

let response;

Given('I have a deployed Lambda function', function () {
  // Assuming the Lambda function is already deployed
});

When('I invoke the Lambda function', async function () {
  const params = {
    FunctionName: 'my-service-dev-hello',
    Payload: JSON.stringify({}),
  };
  
  response = await lambda.invoke(params).promise();
});

Then('I should receive a greeting message', function () {
  const body = JSON.parse(response.Payload);
  if (body.message !== 'Hello, World!') {
    throw new Error(`Expected "Hello, World!" but got "${body.message}"`);
  }
});

Running the Tests

To run the Cucumber tests, you’ll need to set up a test runner. Create a cucumber.js file in the root directory:

module.exports = {
  default: `--format summary --require-module @babel/register --require features/**/*.js`,
};

Then, add the following script to your package.json file:

"scripts": {
  "test": "cucumber-js"
}

Run the tests using the following command:

npm test

Mocking and Stubbing AWS Services

In a real-world scenario, directly invoking AWS services in tests can lead to slow and flaky tests. To address this, you can use the aws-sdk-mock library to mock AWS services. Install the library:

npm install --save-dev aws-sdk-mock

Update your helloSteps.js file to use the mock:

const { Given, When, Then } = require('cucumber');
const AWSMock = require('aws-sdk-mock');
const AWS = require('aws-sdk');

let response;

Given('I have a deployed Lambda function', function () {
  AWSMock.mock('Lambda', 'invoke', (params, callback) => {
    callback(null, {
      Payload: JSON.stringify({
        statusCode: 200,
        body: JSON.stringify({ message: 'Hello, World!' }),
      }),
    });
  });
});

When('I invoke the Lambda function', async function () {
  const lambda = new AWS.Lambda();
  const params = {
    FunctionName: 'my-service-dev-hello',
    Payload: JSON.stringify({}),
  };
  
  response = await lambda.invoke(params).promise();
});

Then('I should receive a greeting message', function () {
  const body = JSON.parse(response.Payload);
  if (body.message !== 'Hello, World!') {
    throw new Error(`Expected "Hello, World!" but got "${body.message}"`);
  }
  
  AWSMock.restore('Lambda');
});

Conclusion

Using Cucumber to test AWS Lambda functions brings the benefits of BDD to serverless architectures. By writing tests in plain language, you can ensure that all stakeholders understand the functionality and requirements of your application. Additionally, mocking AWS services can help you run fast and reliable tests.

If you found this article helpful and are interested in integrating Cucumber Automation Framework with AWS Lambda, I suggest you check out some of the other articles I’ve written for this series:

If you’re looking for a deeper dive into some of the concepts and specifics discussed in my article, feel free to reach out to me directly or as always you can checkout the official AWS Lambda Developer Documentation for more information.

Related Posts