Terraform
Unit Tests
Testing your application can give you faster feedback cycles and guard you against unwanted changes. Testing is currently supported in Typescript with jest and compatible with any testing framework that supports assertions for all other languages.
We generate all files necessary to start testing when you run cdktf init
so that you can start writing tests right away.
Add Testing to Your Application
If you would like to add testing to an existing project, refer the following resources according to your chosen language:
TypeScript: Follow TypeScript's Getting Started guide for testing with Jest. Then, add these lines in a setup file:
const cdktf = require("cdktf"); cdktf.Testing.setupJest();
Python: Follow the Get Started guide for pytest. The assertions for CDKTF are available in the
cdktf
package underTesting
.Java: Follow the Using JUnit documentation. The assertions for CDKTF specific are available in the
cdktf
package underTesting
.C#: Follow the Getting Started with xUnit.net guide. The assertions for CDKTF are available in the
cdktf
package underTesting
.Go: Follow the Add a Test guide in the Go documentation. The assertions for CDKTF specific are available in the
cdktf
package underTesting
.
Write Assertions
The following Typescript example uses Testing.synth
to test a part of the application. Given the desired scope to test, a JSON string representing the synthesized HCL-JSON is returned. Then the custom assertions under Testing
in the cdktf package can be used to verify the code acts as intended. Testing.synth
can test the Stack
that extends the TerraformStack
.
The other examples use Testing.synthScope
to test a part of the application. This creates a scope to test a subset of the application and returns a JSON string representing the synthesized HCL-JSON. Then it uses custom matchers to verify the code acts as intended. Testing.synthScope
can test the Constructs
that extends the IConstruct
.
Note: CDK for Terraform v0.20 introduces support for a Testing.synthHcl
function. However, that is not compatible with other assertions, like toHaveResourceWithProperties
etc. and should not be used.
Examples in
toHaveResource
: Checks if a certain resource existstoHaveResourceWithProperties
: Checks if a certain resource exists with all properties passedtoHaveDataSource
: Checks if a certain data source existstoHaveDataSourceWithProperties
: Checks if a certain data source exists with all properties passedtoHaveProvider
: Checks if a certain provider existstoHaveProviderWithProperties
: Checks if a certain provider exists with all properties passed
import { Testing } from "cdktf";
import { Image } from "../.gen/providers/docker/image";
import { Container } from "../.gen/providers/docker/container";
import MyApplicationsAbstraction from "../app"; // Could be a class extending from Construct
describe("Unit testing using assertions", () => {
it("should contain a container", () => {
const app = Testing.app();
const stack = new MyApplicationsAbstraction(app, "my-app", {});
const synthesized = Testing.synth(stack);
expect(synthesized).toHaveResource(Container);
});
it("should use an ubuntu image", () => {
const app = Testing.app();
const stack = new MyApplicationsAbstraction(app, "my-app", {});
const synthesized = Testing.synth(stack);
expect(synthesized).toHaveResourceWithProperties(Image, {
name: "ubuntu:latest",
});
});
});
Snapshot Testing
Snapshot tests are useful when you want to make sure your infrastructure does not change unexpectedly. Snapshot Testing is only supported in Typescript with Jest. Refer to the Jest docs for details.
import { Testing } from "cdktf";
import { Image } from "../.gen/providers/docker/image";
import { Container } from "../.gen/providers/docker/container";
import MyApplicationsAbstraction from "../app"; // Could be a class extending from Construct
describe("Unit testing using snapshots", () => {
it("Tests a custom abstraction", () => {
expect(
Testing.synthScope((stack) => {
const app = new MyApplicationsAbstraction(scope, "my-app", {});
app.addEndpoint("127.0.0.1"); // This could be a method your class exposes
})
).toMatchInlineSnapshot(); // There is also .toMatchSnapshot() to write the snapshot to a file
});
});
Integration with Terraform
You can produce invalid Terraform configuration if you are using escape hatches in your CDK for Terraform application. You may use an escape hatch when setting up a remote backend or when overriding resource attributes
To test this, you can assert that terraform validate
or terraform plan
run successfully on all or part of your application before running cdktf plan
or cdktf deploy
.
Currently only Typescript is capable of testing for successful plans, while all languages are capable of testing for validity of the Terraform produced.
import { Testing } from "cdktf";
describe("Checking validity", () => {
it("check if the produced terraform configuration is valid", () => {
const app = Testing.app();
const stack = new TerraformStack(app, "test");
const myAbstraction = new MyApplicationsAbstraction(stack, "my-app", {});
myAbstraction.addEndpoint("127.0.0.1"); // This could be a method your class exposes
// We need to do a full synth to validate the terraform configuration
expect(Testing.fullSynth(stack)).toBeValidTerraform();
});
it("check if this can be planned", () => {
const app = Testing.app();
const stack = new TerraformStack(app, "test");
const myAbstraction = new MyApplicationsAbstraction(stack, "my-app", {});
myAbstraction.addEndpoint("127.0.0.1"); // This could be a method your class exposes
// We need to do a full synth to plan the terraform configuration
expect(Testing.fullSynth(stack)).toPlanSuccessfully();
});
});
Integration Testing
CDK for Terraform does not currently offer many helpers for integration testing, but you can create them for your use cases. Here is a recent example: CDK Day 2021.