Unit testing is the process of testing a piece of code or module and identifying any issues within it. In unit testing, we test a piece of code/module with some set of test cases. In JavaScript-based applications, we use generally use Mocha and Chai to write the test cases.
Let us learn how to write unit test cases for the AWS Lambda function using Mocha and Chai.
What is AWS Lambda?
AWS Lambda is a serverless, event-driven compute service that lets you run code for virtually any type of application or backend service without provisioning or managing servers.
Unit testing of AWS lambda functions is also important as it helps us find any issues in the lambda code. In this article, we will be learning more about unit testing the lambda functions.
Let’s get started 🚀
Lambda Code
Let us first take a look into a sample Lambda function that fetches the search results from the database based on the search input and filter. This function takes two inputs — searchText
and filterBy
.
-
searchText
will have the text which we want to search in the database -
filterBy
will have the field name based on which we want to order the search results.
// app.js
async function lambdaFunction(event, context) {
const response = {};
try {
let requestBody = event.body;
let { searchText, filterBy } = requestBody;
/* Validate the required request params */
if (!utils.isValidateInput(searchText) || !utils.isValidateInput(filterBy)) {
throw new Error("Invalid request body");
}
// Get search results
const searchResult = await fetchSearchResult(searchText, filterBy);
if (searchResult && searchResult.length > 0) {
response.data = searchResult;
response.message = "Results fetched!";
} else {
response.data = searchResult || [];
response.message = "No results found";
}
response.code = 200;
return response;
} catch (error) {
response.code = 400;
if (error) {
response.ErrorMessages = [error.message];
}
return response;
}
}
Unit testing of the lambda function
Now let’s test the above lambda code by writing the test cases. For unit testing, we will be using the following packages.
- Mocha - For creating a test suite and running the test cases.
- Chai - Assertion library to verify if a given code is working correctly or not.
- Proxyquire - A package that can proxy the dependencies by overriding the functions inside it.
- Lambda Tester — A package that can help to run a lambda function locally.
Now let’s dive deep into it.
Lambda function execution
For testing the lambda function, we need a way to execute/call a lambda function from our local. For that, we can use a third-party package called lambda-tester. Lambda-tester can take an event
object and execute the lambda function to return the result.
// test.js
const expect = require("chai").expect;
const lambdaTester = require("lambda-tester");
// Import lambda funcion
const lambda = require('../src/lambda/app.js');
const mockData = {
// some mock data
}
// Execute lambda function using lambda-tester package
lambdaTester(lambda.handler)
.event(mockData) // Passing input data
.expectResult((result) => {
// Check if code exist
expect(result.code).to.exist;
// Check if code = 200
expect(result.code).to.equal(200);
// Check if data exist
expect(result.data).to.exist;
// Check if data is an array
expect(result.data).to.be.a("array");
done();
})
.catch(done); // Catch assertion errors
Overriding and mocking the dependencies
Now that we know how to call/execute a lambda function in our local. Let us learn about mocking the dependencies inside the lambda function. These dependencies can be any third-party libraries or DB call or even an API call. To override and mock these dependencies we can use proxyquire package.
Proxyquire will help us import the lambda function without calling (invoking) it and also help us mock the dependencies used inside the lambda function.
In the below example, we have two dependencies — utils (utility functions) and dataService (database functions). We will override a database function called query and add our own logic which will return the mock results. However, we will not override the utility functions file (utils) as it has independent code without any third-party dependencies.
// test.js
const proxyquire = require("proxyquire");
// Internal dependencies
const utils = require("../src/utils/utils");
// Create a object which will have mock functions
const dataStub = {
// Mocking DB call
query: function (params) {
// return some mock results
},
};
// Exporting the lambda with mock dependencies
const lambda = proxyquire.noCallThru().load("../src/lambda/app.js", {
// Replacing the dependencies present inside lambda function (app.js) with mock functions
"../dataService/data": dataStub,
"../utils/utils": utils,
});
Test case for the lambda function
Now that we have learned how to invoke a lambda function in local with mock dependencies. Let us now write a simple test case.
// test.js
const expect = require("chai").expect;
const proxyquire = require("proxyquire");
const lambdaTester = require("lambda-tester");
// Internal dependencies
const utils = require("../src/utils/utils");
// Import mock function from mock.js
const { mockDBfunction, validInput, invalidInput } = require("./mock");
// Define a common test suite
describe("FetchSearchResult Lambda Unit Test", function () {
let lambda = null;
// Mocking data services
let dataStub = {};
beforeEach(function () {
// Exporting the lambda with mock dependencies
lambda = proxyquire.noCallThru().load("../src/lambda/app.js", {
// Replacing the dependencies present inside lambda function (app.js) with mock functions
"../dataService/data": dataStub,
"../utils/utils": utils,
});
});
describe("Successful Invocation", function () {
let mockData = null;
before(function () {
// Attach mock function to data services (mocked)
dataStub = {
...dataStub,
// Mocking DB call
query: function (params) {
// Get the name of the function which is calling 'query' inside lambda function (app.js)
let functionName = arguments.callee.caller.name;
// based on the function name mock the data
return mockDBfunction(functionName);
},
};
// Get valid inputs from mock.js
mockData = validInput();
});
it("with code = 200", function (done) {
// Execute lambda function using lambdaTester package
lambdaTester(lambda.handler)
.event(mockData) // Passing input data
.expectResult((result) => {
// Check if code exist
expect(result.code).to.exist;
// Check if code = 200
expect(result.code).to.equal(200);
// Check if data exist
expect(result.data).to.exist;
// Check if data is an array
expect(result.data).to.be.a("array");
done();
})
.catch(done); // Catch assertion errors
});
});
});
Now let’s run the test case using the command mocha
and check if it is passing or not.
You can find all the code discussed in this article in this repo.
That’s all I have for today. Hope you enjoyed it. 😉
Thank you for stopping by. If you like the content do support me and follow me for more content like this.
Top comments (0)