# 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)