

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 採用測試驅動的開發方法
<a name="development-best-practices"></a>

我們建議您使用 遵循測試驅動型開發 (TDD) 方法 AWS CDK。TDD 是一種軟體開發方法，您可以在其中開發測試案例來指定和驗證程式碼。簡言之，首先為每個功能建立測試案例，如果測試失敗，則編寫新程式碼以通過測試並使程式碼簡單且無錯誤。

您可以先使用 TDD 編寫測試案例。這可協助您在強制執行資源安全政策和遵循專案的唯一命名慣例方面驗證具有不同設計限制的基礎設施。測試 AWS CDK 應用程式的標準方法是使用 AWS CDK [assertions](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.assertions-readme.html) 模組和熱門測試架構，例如 [Jest](https://jestjs.io/) for TypeScript 和 JavaScript 或 [pytest](https://docs.pytest.org/en/6.2.x/) for Python。

您可以為 AWS CDK 應用程式撰寫兩種測試類別：
+ 使用**精細聲明**來測試產生的 CloudFormation 範本的特定方面，例如「此資源具有包含此值的此屬性」。這些測試可以偵測迴歸，並且在您使用 TDD 開發新功能時也很有用 (首先編寫測試，然後透過編寫正確的實作使其通過)。精細聲明是您編寫最多的測試。
+ 使用**快照測試**，以根據先前儲存的基準範本測試合成的 CloudFormation 範本。快照測試使自由重構成為可能，因為您可以確保重構的程式碼與原始程式碼的工作方式完全相同。如果變更是有意為之，您可以接受未來測試的新基準。不過， AWS CDK 升級也可能導致合成範本變更，因此您無法僅依賴快照來確保您的實作正確。

## 單位測試
<a name="unit-test"></a>

本指南專門重點介紹 TypeScript 的單元測試整合。若要啟用測試，請確定您的 `package.json` 檔案具有下列程式庫： `jest`、 `@types/jest`和 `ts-jest` `devDependencies`。若要新增這些套件，請執行 `cdk init lib --language=typescript` 命令。在執行上述命令後，您會看到下列結構。

![\[單元測試結構\]](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/best-practices-cdk-typescript-iac/images/unit_test_structure.png)


下列程式碼是使用 Jest 程式庫啟用`package.json`的檔案範例。

```
{
  ...
  "scripts": {
    "build": "npm run lint && tsc",
    "watch": "tsc -w",
    "test": "jest",
  },
  "devDependencies": {
    ...
    "@types/jest": "27.5.2",
    "jest": "27.5.1",
    "ts-jest": "27.1.5",
    ...
  }
}
```

在 **Test** 資料夾下，您可以編寫測試案例。下列範例顯示 AWS CodePipeline 建構的測試案例。

```
import { Stack } from 'aws-cdk-lib';
import { Template } from 'aws-cdk-lib/assertions';
import * as CodePipeline from 'aws-cdk-lib/aws-codepipeline';
import * as CodePipelineActions from 'aws-cdk-lib/aws-codepipeline-actions';
import { MyPipelineStack } from '../lib/my-pipeline-stack';
test('Pipeline Created with GitHub Source', () => {
  // ARRANGE
  const stack = new Stack();
  // ACT
  new MyPipelineStack(stack, 'MyTestStack');
  // ASSERT
  const template = Template.fromStack(stack);
  // Verify that the pipeline resource is created
  template.resourceCountIs('AWS::CodePipeline::Pipeline', 1);
  // Verify that the pipeline has the expected stages with GitHub source
  template.hasResourceProperties('AWS::CodePipeline::Pipeline', {
    Stages: [
      {
        Name: 'Source',
        Actions: [
          {
            Name: 'SourceAction',
            ActionTypeId: {
              Category: 'Source',
              Owner: 'ThirdParty',
              Provider: 'GitHub',
              Version: '1'
            },
            Configuration: {
              Owner: {
                'Fn::Join': [
                  '',
                  [
                    '{{resolve:secretsmanager:',
                    {
                      Ref: 'GitHubTokenSecret'
                    },
                    ':SecretString:owner}}'
                  ]
                ]
              },
              Repo: {
                'Fn::Join': [
                  '',
                  [
                    '{{resolve:secretsmanager:',
                    {
                      Ref: 'GitHubTokenSecret'
                    },
                    ':SecretString:repo}}'
                  ]
                ]
              },
              Branch: 'main',
              OAuthToken: {
                'Fn::Join': [
                  '',
                  [
                    '{{resolve:secretsmanager:',
                    {
                      Ref: 'GitHubTokenSecret'
                    },
                    ':SecretString:token}}'
                  ]
                ]
              }
            },
            OutputArtifacts: [
              {
                Name: 'SourceOutput'
              }
            ],
            RunOrder: 1
          }
        ]
      },
      {
        Name: 'Build',
        Actions: [
          {
            Name: 'BuildAction',
            ActionTypeId: {
              Category: 'Build',
              Owner: 'AWS',
              Provider: 'CodeBuild',
              Version: '1'
            },
            InputArtifacts: [
              {
                Name: 'SourceOutput'
              }
            ],
            OutputArtifacts: [
              {
                Name: 'BuildOutput'
              }
            ],
            RunOrder: 1
          }
        ]
      }
      // Add more stage checks as needed
    ]
  });
  // Verify that a GitHub token secret is created
  template.resourceCountIs('AWS::SecretsManager::Secret', 1);
});
);
```

若要執行測試，請在專案中執行 `npm run test` 命令。此測試會傳回下列結果。

```
PASS  test/codepipeline-module.test.ts (5.972 s)
  ✓ Code Pipeline Created (97 ms)
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        6.142 s, estimated 9 s
```

如需測試案例的詳細資訊，請參閱《 *AWS Cloud Development Kit (AWS CDK) 開發人員指南*[》中的測試建構](https://docs.aws.amazon.com/cdk/v2/guide/testing.html)。

## 整合測試
<a name="integration-test"></a>

您也可以使用 AWS CDK `integ-tests`模組來包含建構的整合測試。整合測試應定義為 AWS CDK 應用程式。整合測試和 AWS CDK 應用程式之間應該有one-to-one的關係。如需詳細資訊，請參閱《 *AWS CDK API 參考*》中的 [integ-tests-alpha 模組](https://docs.aws.amazon.com/cdk/api/v2/docs/integ-tests-alpha-readme.html)。