Adopt a test-driven development approach - AWS Prescriptive Guidance

Adopt a test-driven development approach

We recommend that you follow a test-driven development (TDD) approach with the AWS CDK. TDD is a software development approach where you develop test cases to specify and validate your code. In simple terms, first you create test cases for each functionality and if the test fails, then you write the new code to pass the test and make the code simple and bug-free.

You can use TDD to write the test case first. This helps you validate the infrastructure with different design constraints in terms of enforcing security policy for the resources and following a unique naming convention for the project. The standard approach to testing AWS CDK applications is to use the AWS CDK assertions module and popular test frameworks, such as Jest for TypeScript and JavaScript or pytest for Python.

There are two categories of tests that you can write for your AWS CDK applications:

  • Use fine-grained assertions to test a specific aspect of the generated CloudFormation template, such as "this resource has this property with this value." These tests can detect regressions and are also useful when you're developing new features using TDD (write a test first, then make it pass by writing a correct implementation). Fine-grained assertions are the tests you'll write the most.

  • Use snapshot tests to test the synthesized CloudFormation template against a previously-stored baseline template. Snapshot tests make it possible to refactor freely, since you can be sure that the refactored code works exactly the same way as the original. If the changes were intentional, you can accept a new baseline for future tests. However, AWS CDK upgrades can also cause synthesized templates to change, so you can't rely only on snapshots to make sure your implementation is correct.

Unit test

This guide focuses on unit test integration for TypeScript specifically. To enable testing, make sure that your package.json file has the following libraries: @types/jestjest, and ts-jest in devDependencies. To add these packages, run the cdk init lib --language=typescript command. After you run the preceding command, you see the following structure.

Unit test structure

The following code is an example of a package.json file that's enabled with the Jest library.

{ ... "scripts": { "build": "npm run lint && tsc", "watch": "tsc -w", "test": "jest", }, "devDependencies": { ... "@types/jest": "27.5.2", "jest": "27.5.1", "ts-jest": "27.1.5", ... } }

Under the Test folder, you can write the test case. The following example shows a test case for an AWS CodePipeline construct.

import {App,Stack} from 'aws-cdk-lib'; import { Template } from 'aws-cdk-lib/assertions'; import * as CodepipelineModule from '../lib/index'; import { Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam'; import { Repository } from 'aws-cdk-lib/aws-codecommit'; import { PipelineProject } from 'aws-cdk-lib/aws-codebuild'; const testData:CodepipelineModule.CodepipelineModuleProps = { pipelineName: "validate-test-pipeline", serviceRoleARN: "", codeCommitRepositoryARN: "", branchName: "master", buildStages:[] } test('Code Pipeline Created', () => { const app = new App(); const stack = new Stack(app, "TestStack"); // WHEN const serviceRole = new Role(stack, "testRole", { assumedBy: new ServicePrincipal('codepipeline.amazonaws.com') }) const codeCommit = new Repository(stack, "testRepo", { repositoryName: "validate-codeCommit-repo" }); const codeBuildProject=new PipelineProject(stack,"TestCodeBuildProject",{}); testData.serviceRoleARN = serviceRole.roleArn; testData.codeCommitRepositoryARN = codeCommit.repositoryArn; testData["buildStages"].push({ stageName:"Deploy", codeBuildProject:codeBuildProject }) new CodepipelineModule.CodepipelineModule(stack, 'MyTestConstruct', testData); // THEN const template = Template.fromStack(stack); template.hasResourceProperties('AWS::CodePipeline::Pipeline', { Name:testData.pipelineName }); });

To run a test, run the npm run test command in your project. The test returns the following results.

PASS test/codepipeline-module.test.ts (5.972 s) ✓ Code Pipeline Created (97 ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 6.142 s, estimated 9 s

For more information on test cases, see Testing constructs in the AWS Cloud Development Kit (AWS CDK) Developer Guide.

Integration test

Integration tests for AWS CDK constructs can also be included by using an integ-tests module. An integration test should be defined as an AWS CDK application. There should be a one-to-one relationship between an integration test and an AWS CDK application. For more information, visit integ-tests-alpha module in the AWS CDK API Reference.