断言是否存在具有CDK自动生成名称的特定S3桶



想象一个玩具CDK堆栈和一个S3 bucket:

import * as cdk from '@aws-cdk/core';
import * as s3 from '@aws-cdk/aws-s3';

export class BucketStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

new s3.Bucket(this, 'MySpecificBucket');
}
}

重要的是,我们只指定了资源的id,而没有指定它的名称(即BucketName)。最好不要依赖特定的名称,因为它们必须是唯一的,所以即使是CDK文档也建议让CDK自动生成名称。这非常好——但是您现在如何在Jest测试用例中测试这个特定bucket的存在?

例如,如果我们有:

import * as cdk from 'aws-cdk-lib';
import { Template } from 'aws-cdk-lib/assertions';
import { BucketStack  } from '../lib/bucket-stack';

let template: Template;

beforeAll(async () => {
const app = new cdk.App();
// WHEN
const stack = new BucketStack(app, 'MyTestStack', {});
// THEN
template = Template.fromStack(stack);
});

describe("My test suite", () => {
test("S3 bucket exists", () => {
template.hasResourceProperties("AWS::S3::Bucket", {
BucketName: "wont-work" // this is autogenerated!
});
});
});

模板将有如下内容:

{
MySpecificBucketF68F3FF0: {
Type: 'AWS::S3::Bucket',
UpdateReplacePolicy: 'Retain',
DeletionPolicy: 'Retain'
}
}

一个可能的解决方案是使用正则表达式检查"MySpecificBucket*"存在,但我想不能保证CDK将自动生成什么样的名称。此外,仅仅通过resourceCountIs计算S3桶的数量是不令人满意的,因为我想断言一个特定桶的存在,而这个桶的名称我并不关心。如果我只指定了id,我如何编写具有这些需求的测试(或者我应该以某种方式改变我的想法)?

这里有几个选项来断言具有特定ID的资源是否存在。

使用转义舱口语法断言:

const bucket = stack.node.tryFindChild("MySpecificBucket");
expect(bucket).toBeDefined();
expect(bucket instanceof s3.Bucket).toBe(true);
expect(bucket?.node.defaultChild instanceof s3.CfnBucket).toBe(true);

使用CDK测试构造和正则表达式断言:

expect(
Object.keys(template.findResources("AWS::S3::Bucket")).find((key) =>
key.match(/^MySpecificBucket[A-F0-9]{8}$/)
)
).toBeDefined();

如果您有许多这样的断言要做,请考虑快照测试。这就是CDK本身的作用。参见@aws-cdk/integ-tests-alpha模块。

他们还故意编写了一个失败的测试,从输出中获取正确的标识符,并在CDK TypeScript研讨会中修复测试。

具体来说,它们是:

$ npm run test
> cdk-workshop@0.1.0 test /home/aws-cdk-intro-workshop
> jest
FAIL  test/hitcounter.test.ts
✓ DynamoDB Table Created (184ms)
✕ Lambda Has Environment Variables (53ms)
● Lambda Has Environment Variables
expect(received).toEqual(expected) // deep equality
- Expected  - 2
+ Received  + 2
Object {
"Variables": Object {
"DOWNSTREAM_FUNCTION_NAME": Object {
-       "Ref": "TestFunctionXXXXX",
+       "Ref": "TestFunction22AD90FC",
},
"HITS_TABLE_NAME": Object {
-       "Ref": "MyTestConstructHitsXXXXX",
+       "Ref": "MyTestConstructHits24A357F0",
},
},
}
37 |     Environment: envCapture,
38 |   });
> 39 |   expect(envCapture.asObject()).toEqual(
|                                 ^
40 |     {
41 |       Variables: {
42 |         DOWNSTREAM_FUNCTION_NAME: {
at Object.<anonymous> (test/hitcounter.test.ts:39:33)
Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 passed, 2 total
Snapshots:   0 total
Time:        3.971 s, estimated 4 s
Ran all test suites.

我想如果有更好的选择,他们是不会提倡这种方法的。

最新更新