Should I test that?

Should I unit test CDK code?

Verdict

Yes

Yes, unit test CDK code minimally: one test per stack that asserts its tables and buckets keep their logical IDs; leave wiring errors to the staging deploy, and do not assert every declared property.

Why

Yes, unit test CDK code minimally: one test per stack that pins the logical IDs of the tables and buckets that hold data. The typical case is a TypeScript CDK app with Lambda functions, an API, a DynamoDB table and a bucket, deployed to staging before production. Blast radius is users, because a broken stack takes a feature down, and Change frequency is regularly, because the stack changes with features. Detectability is same-day, because a missing grant fails the staging deploy or its integration tests, and Reversibility is with-effort: another pipeline run plus follow-up on failed requests. Test cost is moderate, because Template.fromStack bundles every Lambda asset and needs updates when the stack changes, so rule R12 gives Test minimally.

When the decision changes
WhenDecisionWhy
Your CDK construct branches on the stage, so some alarms exist only in the production templateTest: synthesize the stack with each stage's props and assert the settings that differDetectability moves to eventually, because staging deploys the other branch
An S3 bucket defined in CDK holds personal data, such as identity documentsTest mandatory: assert Block Public Access, encryption and no wildcard principal in the bucket policyBlast radius rises to safety-or-legal and Detectability to never, because a public bucket serves files with no error
Other teams install your CDK constructs as a packageTest: one fine-grained assertion for each prop combination that changes the templateDetectability moves to eventually, because a break shows in stacks the author never deploys
The CDK stack holds no data, and each pull request deploys it to its own stage where integration tests call every routeDo not unit test the template; keep the deploy per pull request and its integration testsDetectability rises to immediately and Reversibility falls to trivial, because a redeploy leaves nothing behind
Tables or databases in the stack declare deletion protection or point-in-time recoveryTest: assert those settings in the synthesized template of each stackDetectability moves to eventually, because a dropped setting deploys without an error and shows only when the data is needed
The failure you fear is a console edit in the AWS account, not a change to the CDK templateTest it differently: turn on the AWS Config drift detection rule and alert when a stack driftsTest cost rises to prohibitive, because a template test cannot see the account, and Detectability moves to eventually

What breaks if you don't test

Most CDK mistakes fail loudly in staging. The quiet one is a refactor that moves a table to a new place in the construct tree. The CDK builds the logical ID from that path, and when the ID changes, CloudFormation creates a new resource and deletes the old one. With the default RETAIN policy the old table survives outside the stack, the functions switch to an empty table, and customers report missing data.

What you lose if you over-test

Fine-grained assertions on every property repeat the stack line by line, so each change is made twice, the cost Yan Cui describes for declarative stacks. A snapshot of the whole template fails on CDK upgrades, as the CDK testing guide warns, and on every handler edit, because the template carries each Lambda asset's hash.

How to test

Use the assertions module with Jest or pytest:

  1. One test per stack, synthesized with production props, that asserts the logical ID and Retain policy of each table, bucket and database, as the CDK guide advises.
  2. A regression test when a bug reaches the stack.

Staging cannot catch a changed ID: the deploy replaces the staging table too, and tests that seed their own data pass.

When the answer changes

  • Your constructs branch on the stage.
  • A bucket or policy guards personal data.
  • Other teams install your constructs.

Real incident + Code example

The orders table that moved

On an order service I worked on, a developer moved the DynamoDB orders table into a new Storage construct, and its logical ID changed. Staging integration tests passed, because they create their own orders. In production CloudFormation created an empty table, kept the old one outside the stack, and gave the functions the new name. Customers saw empty order histories for 40 minutes. Recovery took most of a day: cdk import brought the old table back, and a script copied the orders written in between. The test we added fails on that refactor:

import { App } from "aws-cdk-lib";
import { Template } from "aws-cdk-lib/assertions";
import { OrdersStack } from "../lib/orders-stack";
import { prodProps } from "../lib/stages";

test("stateful resources keep their logical IDs", () => {
  const stack = new OrdersStack(new App(), "Orders", prodProps);
  const template = Template.fromStack(stack);

  // A new ID here makes CloudFormation create an empty replacement.
  expect(Object.keys(template.findResources("AWS::DynamoDB::Table")))
    .toEqual(["OrdersTable8A3C5F21"]);
  expect(Object.keys(template.findResources("AWS::S3::Bucket")))
    .toEqual(["AttachmentsBucket4F1D2B90"]);

  template.hasResource("AWS::DynamoDB::Table", {
    DeletionPolicy: "Retain",
    UpdateReplacePolicy: "Retain",
  });
});

FAQ

Do you need to unit test CDK against the synthesized CloudFormation template?

Yes, test the synthesized CDK template for what a deploy does not reveal: logical IDs of stateful resources, settings that differ by stage, and protective settings on data.

Are CDK snapshot tests worth it?

No, a snapshot of the whole CDK template does not pay off as a permanent test, because it fails on CDK upgrades and on every Lambda code edit. Keep one only for a refactor that should leave the template unchanged.

How do I stop a CDK refactor from replacing a DynamoDB table?

Keep the table's construct path, or, when you wrap the table in a new construct, give that construct the table's old ID and the table the ID Default. Pin the table's logical ID in a unit test so that a changed path fails CI.

Should I test custom CDK constructs?

Yes, test a custom CDK construct that branches on its props or that other teams install, with one assertion for each prop combination that changes the template. A construct used once in your own stack needs only the stack's logical ID test.