# CDK - Testing Constructs 2 :::info 日期 : 2025/04/26 ::: 以下以 [Testing Constructs](https://catalog.us-east-1.prod.workshops.aws/workshops/10141411-0192-4021-afa8-2436f3c66bd8/en-US/2000-typescript-workshop/600-advanced-topics/650-construct-testing/670-validation-tests) 作為講解 步驟與完整程式碼 請參考上述網站 ------- #### Validation Tests 目的是希望讓使用者(或別的工程師)把參數設定在一定限制條件內。 這裡希望把 DynamoDB Table 的 readCapacity 限制於大於5小於20的範圍內,有以下步驟 1. Interface 在 interface 裡加上 readCapacity,讓外部在建立 HitCounter 時,可以傳 readCapacity 參數進來。 *讓使用者可以設定 ```typescript // 定義一個介面 HitCounterProps,讓外部資源傳進來 export interface HitCounterProps { downstream: IFunction; /** * The read capacity units for the table * * Must be greater than 5 and lower than 20 * * @default 5 */ readCapacity?: number; } ``` 2. 加入 Property 把 readCapacity 加進來 DynamoDB Table,並加上 Validation 驗證邏輯,有傳 readCapacity,就用傳進來的值,如果是 undefined,就用預設值 5 *拿設定來建資源 ```typescript // 建立一個 DynamoDB 表格,用來儲存「每個路徑的點擊次數」 const table = new Table(this, "Hits", { partitionKey: { name: "path", type: AttributeType.STRING }, // key 是 path 是 str encryption: TableEncryption.AWS_MANAGED, readCapacity: props.readCapacity ?? 5, // ?? 語法 : 有值 -> 用左邊的值 / null 或 undefined -> 用右邊的預設值 }); ``` 3. Error 如果 readCapacity 不合理,就要 throw error *在建之前先檢查對不對 ```typescript constructor(scope: Construct, id: string, props: HitCounterProps) { // 如果 props.readCapacity 有設定 且 readCapacity 小於 5 或大於 20 if (props.readCapacity !== undefined && (props.readCapacity < 5 || props.readCapacity > 20)) { throw new Error("readCapacity must be greater than 5 and less than 20"); // 拋出一個錯誤 } ``` --- #### 測試 故意傳一個錯的 readCapacity = 3,確認 HitCounter 會正確丟出錯誤,確保未來使用者會被報錯 ```typescript // test/hitcounter.test.ts // 設定 readCapacity 低於允許範圍,應該要丟出錯誤 test("read capacity can be configured", () => { // 建立一個新的空 Stack const stack = new Stack(); // 期待:當用錯誤的 readCapacity 建 HitCounter 時,會丟出特定錯誤 expect(() => { // 嘗試建立 HitCounter,故意設定 readCapacity = 3(低於5) new HitCounter(stack, "MyTestConstruct", { downstream: new Function(stack, "TestFunction", { runtime: Runtime.NODEJS_22_X, handler: "hello.handler", code: Code.fromAsset("lambda"), }), readCapacity: 3, // 故意設錯 }); }) // 驗證:要丟出的錯誤訊息,符合這個正則表達式 .toThrowError(/readCapacity must be greater than 5 and less than 20/); }); ``` 結果 ```bash PASS test/hitcounter.test.ts (46.98 s) ✓ DynamoDB Table Created (10729 ms) ✓ Lambda Has Environment Variables (282 ms) ✓ DynamoDB Table Created With Encryption (57 ms) ✓ read capacity can be configured (85 ms) Test Suites: 1 passed, 1 total Tests: 4 passed, 4 total pshots: 0 total Time: 49.592 s, estimated 51 s ``` 幾個可以討論的點 1. 為什麼 HitCounter 物件不像之前一樣在 test 建立? 這次物件被放在 `expect(() => { ... })` 裡面,因為如果物件不符合建立條件的話,會直接回傳錯誤,而 expect 可以去捕捉錯誤 ```typescript // 錯誤寫法 new HitCounter(stack, "MyTestConstruct", { downstream: new Function(...), readCapacity: 3, }); expect(...).toThrowError(...); ``` 如果像之前這樣寫,HitCounter 建立時就會馬上拋出錯誤,整個測試程式就會 crash,跑不到 expect 區域 2. 為什麼最後跑 test 是通過? 因為錯誤訊息有對上,`expect(結果).toBe(預期值)`,如果結果和預期值相同,則測試通過。 整個邏輯是我們故意設低 readCapacity,讓在建立 HitCounter 時,會丟出 `"readCapacity must be greater than 5 and less than 20"` 錯誤訊息 而測試裡的 `expect(...).toThrowError(/readCapacity must be greater than 5 and less than 20/)`,錯誤訊息有對上正則表達式,所以這個 test 是通過 --- [Testing Constructs](https://catalog.us-east-1.prod.workshops.aws/workshops/10141411-0192-4021-afa8-2436f3c66bd8/en-US/2000-typescript-workshop/600-advanced-topics/650-construct-testing/670-validation-tests)