

這是 AWS CDK v2 開發人員指南。較舊的 CDK v1 已於 2022 年 6 月 1 日進入維護，並於 2023 年 6 月 1 日結束支援。

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

# 測試 AWS CDK 應用程式
<a name="testing"></a>

使用 AWS CDK，您的基礎設施可以與您撰寫的任何其他程式碼一樣可測試。您可以在雲端和本機進行測試。本主題說明如何在雲端測試 。如需本機測試的指引，請參閱[使用 SAM CLI AWS 本機測試和建置 AWS CDK 應用程式](testing-locally.md)。測試 AWS CDK 應用程式的標準方法使用 AWS CDK 的[聲明](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 應用程式撰寫兩種測試類別。
+  **精細聲明**會測試 generated AWS CloudFormation 範本的特定層面，例如「此資源具有此值的此屬性」。這些測試可以偵測迴歸。當您使用測試驅動的開發來開發新功能時，它們也很有用。（您可以先撰寫測試，然後撰寫正確的實作，讓測試通過。) 精細聲明是最常使用的測試。
+  **快照測試**會根據先前存放的基準範本來測試合成的 AWS CloudFormation 範本。快照測試可讓您自由重構，因為您可以確定重構程式碼的運作方式與原始程式碼完全相同。如果變更是有意為之，您可以接受未來測試的新基準。不過，CDK 升級也可能導致合成範本變更，因此您無法僅依賴快照來確保您的實作正確。

**注意**  
作為本主題範例的完整 TypeScript、Python 和 Java 應用程式版本可在 [ GitHub 上取得](https://github.com/cdklabs/aws-cdk-testing-examples/)。

## 開始使用
<a name="testing-getting-started"></a>

為了說明如何撰寫這些測試，我們將建立包含 AWS Step Functions 狀態機器和 AWS Lambda 函數的堆疊。Lambda 函數已訂閱 Amazon SNS 主題，並直接將訊息轉送至狀態機器。

首先，使用 CDK Toolkit 建立空的 CDK 應用程式專案，並安裝我們需要的程式庫。我們將使用的建構模組都在主要 CDK 套件中，這是使用 CDK Toolkit 建立之專案的預設相依性。不過，您必須安裝測試架構。

**Example**  

```
$ mkdir state-machine && cd state-machine
cdk init --language=typescript
npm install --save-dev jest @types/jest
```
為您的測試建立目錄。  

```
$ mkdir test
```
編輯專案的 `package.json` 以告知 NPM 如何執行 Jest，並告知 Jest 要收集哪些類型的檔案。必要的變更如下所示。  
+ 將新`test`金鑰新增至 `scripts`區段
+ 將 Jest 及其類型新增至 `devDependencies`區段
+ 使用`moduleFileExtensions`宣告新增`jest`最上層金鑰
這些變更會顯示在下列大綱中。將新文字放在 中指示的位置`package.json`。「...」預留位置表示檔案的現有部分不應變更。  

```
{
  ...
  "scripts": {
    ...
    "test": "jest"
  },
  "devDependencies": {
    ...
    "@types/jest": "^24.0.18",
    "jest": "^24.9.0"
  },
  "jest": {
    "moduleFileExtensions": ["js"]
  }
}
```

```
$ mkdir state-machine && cd state-machine
$ cdk init --language=javascript
$ npm install --save-dev jest
```
為您的測試建立目錄。  

```
$ mkdir test
```
編輯專案的 `package.json` 以告知 NPM 如何執行 Jest，並告知 Jest 要收集哪些類型的檔案。必要的變更如下所示。  
+ 將新`test`金鑰新增至 `scripts`區段
+ 將 Jest 新增至 `devDependencies`區段
+ 使用`moduleFileExtensions`宣告新增`jest`最上層金鑰
這些變更會顯示在下列大綱中。將新文字放在 中指示的位置`package.json`。「...」預留位置表示檔案的現有部分不應變更。  

```
{
  ...
  "scripts": {
    ...
    "test": "jest"
  },
  "devDependencies": {
    ...
    "jest": "^24.9.0"
  },
  "jest": {
    "moduleFileExtensions": ["js"]
  }
}
```

```
$ mkdir state-machine && cd state-machine
$ cdk init --language=python
$ source .venv/bin/activate # On Windows, run '.\venv\Scripts\activate' instead
$ python -m pip install -r requirements.txt
$ python -m pip install -r requirements-dev.txt
```

```
$ mkdir state-machine && cd-state-machine
$ cdk init --language=java
```
在您偏好的 Java IDE 中開啟專案。（在 Eclipse 中，使用**檔案** > **匯入** > 現有 Maven 專案。)

```
$ mkdir state-machine && cd-state-machine
$ cdk init --language=csharp
```
在 Visual Studio `src\StateMachine.sln`中開啟 。  
在解決方案總管中的解決方案上按一下滑鼠右鍵，然後選擇**新增** > **新專案**。搜尋 MSTest C\$1 並新增 C\$1 的 **MSTest 測試專案**。（預設名稱 `TestProject1` 沒問題。)  
按一下滑鼠右鍵`TestProject1`並選擇**新增** > **專案參考**，然後新增`StateMachine`專案做為參考。

## 堆疊範例
<a name="testing-app"></a>

以下是本主題中將測試的堆疊。如先前所述，其中包含 Lambda 函數和 Step Functions 狀態機器，並接受一或多個 Amazon SNS 主題。Lambda 函數已訂閱 Amazon SNS 主題，並將其轉送至狀態機器。

您不需要執行任何特殊動作，即可測試應用程式。事實上，此 CDK 堆疊與本指南中的其他範例堆疊沒有任何重要差異。

**Example**  
在 中放置下列程式碼`lib/state-machine-stack.ts`：  

```
import * as cdk from "aws-cdk-lib";
import * as sns from "aws-cdk-lib/aws-sns";
import * as sns_subscriptions from "aws-cdk-lib/aws-sns-subscriptions";
import * as lambda from "aws-cdk-lib/aws-lambda";
import * as sfn from "aws-cdk-lib/aws-stepfunctions";
import { Construct } from "constructs";

export interface StateMachineStackProps extends cdk.StackProps {
  readonly topics: sns.Topic[];
}

export class StateMachineStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props: StateMachineStackProps) {
    super(scope, id, props);

    // In the future this state machine will do some work...
    const stateMachine = new sfn.StateMachine(this, "StateMachine", {
      definition: new sfn.Pass(this, "StartState"),
    });

    // This Lambda function starts the state machine.
    const func = new lambda.Function(this, "LambdaFunction", {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: "handler",
      code: lambda.Code.fromAsset("./start-state-machine"),
      environment: {
        STATE_MACHINE_ARN: stateMachine.stateMachineArn,
      },
    });
    stateMachine.grants.startExecution(func);

    const subscription = new sns_subscriptions.LambdaSubscription(func);
    for (const topic of props.topics) {
      topic.addSubscription(subscription);
    }
  }
}
```
在 中放置下列程式碼`lib/state-machine-stack.js`：  

```
const cdk = require("aws-cdk-lib");
const sns = require("aws-cdk-lib/aws-sns");
const sns_subscriptions = require("aws-cdk-lib/aws-sns-subscriptions");
const lambda = require("aws-cdk-lib/aws-lambda");
const sfn = require("aws-cdk-lib/aws-stepfunctions");

class StateMachineStack extends cdk.Stack {
  constructor(scope, id, props) {
    super(scope, id, props);

    // In the future this state machine will do some work...
    const stateMachine = new sfn.StateMachine(this, "StateMachine", {
      definition: new sfn.Pass(this, "StartState"),
    });

    // This Lambda function starts the state machine.
    const func = new lambda.Function(this, "LambdaFunction", {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: "handler",
      code: lambda.Code.fromAsset("./start-state-machine"),
      environment: {
        STATE_MACHINE_ARN: stateMachine.stateMachineArn,
      },
    });
    stateMachine.grants.startExecution(func);

    const subscription = new sns_subscriptions.LambdaSubscription(func);
    for (const topic of props.topics) {
      topic.addSubscription(subscription);
    }
  }
}

module.exports = { StateMachineStack }
```
在 中放置下列程式碼`state_machine/state_machine_stack.py`：  

```
from typing import List

import aws_cdk.aws_lambda as lambda_
import aws_cdk.aws_sns as sns
import aws_cdk.aws_sns_subscriptions as sns_subscriptions
import aws_cdk.aws_stepfunctions as sfn
import aws_cdk as cdk

class StateMachineStack(cdk.Stack):
    def __init__(
        self,
        scope: cdk.Construct,
        construct_id: str,
        *,
        topics: List[sns.Topic],
        **kwargs
    ) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # In the future this state machine will do some work...
        state_machine = sfn.StateMachine(
            self, "StateMachine", definition=sfn.Pass(self, "StartState")
        )

        # This Lambda function starts the state machine.
        func = lambda_.Function(
            self,
            "LambdaFunction",
            runtime=lambda_.Runtime.NODEJS_18_X,
            handler="handler",
            code=lambda_.Code.from_asset("./start-state-machine"),
            environment={
                "STATE_MACHINE_ARN": state_machine.state_machine_arn,
            },
        )
        state_machine.grants.start_execution(func)

        subscription = sns_subscriptions.LambdaSubscription(func)
        for topic in topics:
            topic.add_subscription(subscription)
```

```
package software.amazon.samples.awscdkassertionssamples;

import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.services.lambda.Code;
import software.amazon.awscdk.services.lambda.Function;
import software.amazon.awscdk.services.lambda.Runtime;
import software.amazon.awscdk.services.sns.ITopicSubscription;
import software.amazon.awscdk.services.sns.Topic;
import software.amazon.awscdk.services.sns.subscriptions.LambdaSubscription;
import software.amazon.awscdk.services.stepfunctions.Pass;
import software.amazon.awscdk.services.stepfunctions.StateMachine;

import java.util.Collections;
import java.util.List;

public class StateMachineStack extends Stack {
    public StateMachineStack(final Construct scope, final String id, final List<Topic> topics) {
        this(scope, id, null, topics);
    }

    public StateMachineStack(final Construct scope, final String id, final StackProps props, final List<Topic> topics) {
        super(scope, id, props);

        // In the future this state machine will do some work...
        final StateMachine stateMachine = StateMachine.Builder.create(this, "StateMachine")
                .definition(new Pass(this, "StartState"))
                .build();

        // This Lambda function starts the state machine.
        final Function func = Function.Builder.create(this, "LambdaFunction")
                .runtime(Runtime.NODEJS_18_X)
                .handler("handler")
                .code(Code.fromAsset("./start-state-machine"))
                .environment(Collections.singletonMap("STATE_MACHINE_ARN", stateMachine.getStateMachineArn()))
                .build();
        stateMachine.getGrants().startExecution(func);

        final ITopicSubscription subscription = new LambdaSubscription(func);
        for (final Topic topic : topics) {
            topic.addSubscription(subscription);
        }
    }
}
```

```
using Amazon.CDK;
using Amazon.CDK.AWS.Lambda;
using Amazon.CDK.AWS.StepFunctions;
using Amazon.CDK.AWS.SNS;
using Amazon.CDK.AWS.SNS.Subscriptions;
using Constructs;

using System.Collections.Generic;

namespace AwsCdkAssertionSamples
{
    public class StateMachineStackProps : StackProps
    {
        public Topic[] Topics;
    }

    public class StateMachineStack : Stack
    {

        internal StateMachineStack(Construct scope, string id, StateMachineStackProps props = null) : base(scope, id, props)
        {
            // In the future this state machine will do some work...
            var stateMachine = new StateMachine(this, "StateMachine", new StateMachineProps
            {
                Definition = new Pass(this, "StartState")
            });

            // This Lambda function starts the state machine.
            var func = new Function(this, "LambdaFunction", new FunctionProps
            {
                Runtime = Runtime.NODEJS_18_X,
                Handler = "handler",
                Code = Code.FromAsset("./start-state-machine"),
                Environment = new Dictionary<string, string>
                {
                    { "STATE_MACHINE_ARN", stateMachine.StateMachineArn }
                }
            });
            stateMachine.Grants.StartExecution(func);

            foreach (Topic topic in props?.Topics ?? new Topic[0])
            {
                var subscription = new LambdaSubscription(func);
            }

        }
    }
}
```

我們將修改應用程式的主要進入點，以便我們不會實際執行個體化堆疊。我們不想意外部署它。我們的測試會建立應用程式和堆疊執行個體以供測試。當 與測試驅動的開發結合時，這是一個有用的策略：在啟用部署之前，請確保堆疊通過所有測試。

**Example**  
在 `bin/state-machine.ts` 中：  

```
#!/usr/bin/env node
import * as cdk from "aws-cdk-lib";

const app = new cdk.App();

// Stacks are intentionally not created here -- this application isn't meant to
// be deployed.
```
在 `bin/state-machine.js` 中：  

```
#!/usr/bin/env node
const cdk = require("aws-cdk-lib");

const app = new cdk.App();

// Stacks are intentionally not created here -- this application isn't meant to
// be deployed.
```
在 `app.py` 中：  

```
#!/usr/bin/env python3
import os

import aws_cdk  as cdk

app = cdk.App()

# Stacks are intentionally not created here -- this application isn't meant to
# be deployed.

app.synth()
```

```
package software.amazon.samples.awscdkassertionssamples;

import software.amazon.awscdk.App;

public class SampleApp {
    public static void main(final String[] args) {
        App app = new App();

        // Stacks are intentionally not created here -- this application isn't meant to be deployed.

        app.synth();
    }
}
```

```
using Amazon.CDK;

namespace AwsCdkAssertionSamples
{
    sealed class Program
    {
        public static void Main(string[] args)
        {
            var app = new App();

            // Stacks are intentionally not created here -- this application isn't meant to be deployed.

            app.Synth();
        }
    }
}
```

## Lambda 函數
<a name="testing-lambda"></a>

我們的範例堆疊包含 Lambda 函數，可啟動我們的狀態機器。我們必須提供此函數的原始碼，以便 CDK 可以綁定和部署它，作為建立 Lambda 函數資源的一部分。
+ 在`start-state-machine`應用程式的主目錄中建立 資料夾。
+ 在此資料夾中，建立至少一個檔案。例如，您可以將下列程式碼儲存在 中`start-state-machines/index.js`。

  ```
  exports.handler = async function (event, context) {
  	return 'hello world';
  };
  ```

  不過，任何檔案都可以運作，因為我們實際上不會部署堆疊。

## 執行測試
<a name="testing-running-tests"></a>

以下是您在 AWS CDK 應用程式中用來執行測試的命令，供您參考。這些命令與您用來在任何使用相同測試架構的專案中執行測試的命令相同。對於需要建置步驟的語言，請包含 ，以確保您的測試已編譯。

**Example**  

```
$ tsc && npm test
```

```
$ npm test
```

```
$ python -m pytest
```

```
$ mvn compile && mvn test
```
建置您的解決方案 (F6) 以探索測試，然後執行測試 (**測試** > **執行所有測試**)。若要選擇要執行的測試，請開啟 Test Explorer (**測試** > **Test Explorer**)。  
或者：  

```
$ dotnet test src
```

## 精細的聲明
<a name="testing-fine-grained"></a>

使用精細聲明測試堆疊的第一個步驟是合成堆疊，因為我們要針對 generated AWS CloudFormation 範本撰寫聲明。

我們的 `StateMachineStackStack` 要求我們將 Amazon SNS 主題傳遞給它，以轉送至狀態機器。因此，在我們的測試中，我們將建立單獨的堆疊來包含主題。

通常，撰寫 CDK 應用程式時，您可以在堆疊的建構函數中子類別`Stack`並執行個體化 Amazon SNS 主題。在我們的測試中，我們會`Stack`直接執行個體化，然後將此堆疊作為 `Topic`的範圍傳遞，將其連接到堆疊。這在功能上相當且較不詳細。它也有助於讓僅用於測試的堆疊與您打算部署的堆疊「看起來不同」。

**Example**  

```
import { Capture, Match, Template } from "aws-cdk-lib/assertions";
import * as cdk from "aws-cdk-lib";
import * as sns from "aws-cdk-lib/aws-sns";
import { StateMachineStack } from "../lib/state-machine-stack";

describe("StateMachineStack", () => {
  test("synthesizes the way we expect", () => {
    const app = new cdk.App();

    // Since the StateMachineStack consumes resources from a separate stack
    // (cross-stack references), we create a stack for our SNS topics to live
    // in here. These topics can then be passed to the StateMachineStack later,
    // creating a cross-stack reference.
    const topicsStack = new cdk.Stack(app, "TopicsStack");

    // Create the topic the stack we're testing will reference.
    const topics = [new sns.Topic(topicsStack, "Topic1", {})];

    // Create the StateMachineStack.
    const stateMachineStack = new StateMachineStack(app, "StateMachineStack", {
      topics: topics, // Cross-stack reference
    });

    // Prepare the stack for assertions.
    const template = Template.fromStack(stateMachineStack);
  })
})
```

```
const { Capture, Match, Template } = require("aws-cdk-lib/assertions");
const cdk = require("aws-cdk-lib");
const sns = require("aws-cdk-lib/aws-sns");
const { StateMachineStack } = require("../lib/state-machine-stack");

describe("StateMachineStack", () => {
  test("synthesizes the way we expect", () => {
    const app = new cdk.App();

    // Since the StateMachineStack consumes resources from a separate stack
    // (cross-stack references), we create a stack for our SNS topics to live
    // in here. These topics can then be passed to the StateMachineStack later,
    // creating a cross-stack reference.
    const topicsStack = new cdk.Stack(app, "TopicsStack");

    // Create the topic the stack we're testing will reference.
    const topics = [new sns.Topic(topicsStack, "Topic1", {})];

    // Create the StateMachineStack.
    const StateMachineStack = new StateMachineStack(app, "StateMachineStack", {
      topics: topics, // Cross-stack reference
    });

    // Prepare the stack for assertions.
    const template = Template.fromStack(stateMachineStack);
  })
})
```

```
from aws_cdk import aws_sns as sns
import aws_cdk as cdk
from aws_cdk.assertions import Template

from app.state_machine_stack import StateMachineStack

def test_synthesizes_properly():
    app = cdk.App()

    # Since the StateMachineStack consumes resources from a separate stack
    # (cross-stack references), we create a stack for our SNS topics to live
    # in here. These topics can then be passed to the StateMachineStack later,
    # creating a cross-stack reference.
    topics_stack = cdk.Stack(app, "TopicsStack")

    # Create the topic the stack we're testing will reference.
    topics = [sns.Topic(topics_stack, "Topic1")]

    # Create the StateMachineStack.
    state_machine_stack = StateMachineStack(
        app, "StateMachineStack", topics=topics  # Cross-stack reference
    )

    # Prepare the stack for assertions.
    template = Template.from_stack(state_machine_stack)
```

```
package software.amazon.samples.awscdkassertionssamples;

import org.junit.jupiter.api.Test;
import software.amazon.awscdk.assertions.Capture;
import software.amazon.awscdk.assertions.Match;
import software.amazon.awscdk.assertions.Template;
import software.amazon.awscdk.App;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.services.sns.Topic;

import java.util.*;

import static org.assertj.core.api.Assertions.assertThat;

public class StateMachineStackTest {
    @Test
    public void testSynthesizesProperly() {
        final App app = new App();

        // Since the StateMachineStack consumes resources from a separate stack (cross-stack references), we create a stack
        // for our SNS topics to live in here. These topics can then be passed to the StateMachineStack later, creating a
        // cross-stack reference.
        final Stack topicsStack = new Stack(app, "TopicsStack");

        // Create the topic the stack we're testing will reference.
        final List<Topic> topics = Collections.singletonList(Topic.Builder.create(topicsStack, "Topic1").build());

        // Create the StateMachineStack.
        final StateMachineStack stateMachineStack = new StateMachineStack(
                app,
                "StateMachineStack",
                topics // Cross-stack reference
        );

        // Prepare the stack for assertions.
        final Template template = Template.fromStack(stateMachineStack)
    }
}
```

```
using Microsoft.VisualStudio.TestTools.UnitTesting;

using Amazon.CDK;
using Amazon.CDK.AWS.SNS;
using Amazon.CDK.Assertions;
using AwsCdkAssertionSamples;

using ObjectDict = System.Collections.Generic.Dictionary<string, object>;
using StringDict = System.Collections.Generic.Dictionary<string, string>;

namespace TestProject1
{
    [TestClass]
    public class StateMachineStackTest
    {
        [TestMethod]
        public void TestMethod1()
        {
            var app = new App();

            // Since the StateMachineStack consumes resources from a separate stack (cross-stack references), we create a stack
            // for our SNS topics to live in here. These topics can then be passed to the StateMachineStack later, creating a
            // cross-stack reference.
            var topicsStack = new Stack(app, "TopicsStack");

            // Create the topic the stack we're testing will reference.
            var topics = new Topic[] { new Topic(topicsStack, "Topic1") };

            // Create the StateMachineStack.
            var StateMachineStack = new StateMachineStack(app, "StateMachineStack", new StateMachineStackProps
            {
                Topics = topics
            });

            // Prepare the stack for assertions.
            var template = Template.FromStack(stateMachineStack);

            // test will go here
        }
    }
}
```

現在，我們可以宣告 Lambda 函數和 Amazon SNS 訂閱已建立。

**Example**  

```
    // Assert it creates the function with the correct properties...
    template.hasResourceProperties("AWS::Lambda::Function", {
      Handler: "handler",
      Runtime: "nodejs14.x",
    });

    // Creates the subscription...
    template.resourceCountIs("AWS::SNS::Subscription", 1);
```

```
    // Assert it creates the function with the correct properties...
    template.hasResourceProperties("AWS::Lambda::Function", {
      Handler: "handler",
      Runtime: "nodejs14.x",
    });

    // Creates the subscription...
    template.resourceCountIs("AWS::SNS::Subscription", 1);
```

```
# Assert that we have created the function with the correct properties
    template.has_resource_properties(
        "AWS::Lambda::Function",
        {
            "Handler": "handler",
            "Runtime": "nodejs14.x",
        },
    )

    # Assert that we have created a subscription
    template.resource_count_is("AWS::SNS::Subscription", 1)
```

```
        // Assert it creates the function with the correct properties...
        template.hasResourceProperties("AWS::Lambda::Function", Map.of(
                "Handler", "handler",
                "Runtime", "nodejs14.x"
        ));

         // Creates the subscription...
        template.resourceCountIs("AWS::SNS::Subscription", 1);
```

```
            // Prepare the stack for assertions.
            var template = Template.FromStack(stateMachineStack);

            // Assert it creates the function with the correct properties...
            template.HasResourceProperties("AWS::Lambda::Function", new StringDict {
                { "Handler", "handler"},
                { "Runtime", "nodejs14x" }
            });

            // Creates the subscription...
            template.ResourceCountIs("AWS::SNS::Subscription", 1);
```

我們的 Lambda 函數測試宣告函數資源的兩個特定屬性具有特定值。根據預設， `hasResourceProperties`方法會對資源的屬性執行部分比對，如合成的 CloudFormation 範本中所指定。此測試需要提供的屬性存在並具有指定的值，但資源也可以具有其他未測試的屬性。

我們的 Amazon SNS 聲明會宣告合成的範本包含訂閱，但不包含訂閱本身。我們主要包含此聲明，以說明如何聲明資源計數。`Template` 類別提供更具體的方法，以針對 CloudFormation 範本的 `Resources`、 `Outputs`和 `Mapping`區段撰寫宣告。<a name="testing-fine-grained-matchers"></a>

 **配對者**   
的預設部分比對行為`hasResourceProperties`可以使用 ` [Match](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.assertions.Match.html#methods) `類別中的*配對器*進行變更。  
相符項目的範圍從寬鬆 (`Match.anyValue`) 到嚴格 (`Match.objectEquals`)。它們可以巢狀化，將不同的比對方法套用至資源屬性的不同部分。例如，使用 `Match.objectEquals`和 `Match.anyValue`一起，我們可以更完整地測試狀態機器的 IAM 角色，同時不需要屬性可能變更的特定值。  

**Example**  

```
    // Fully assert on the state machine's IAM role with matchers.
    template.hasResourceProperties(
      "AWS::IAM::Role",
      Match.objectEquals({
        AssumeRolePolicyDocument: {
          Version: "2012-10-17",		 	 	 
          Statement: [
            {
              Action: "sts:AssumeRole",
              Effect: "Allow",
              Principal: {
                Service: {
                  "Fn::Join": [
                    "",
                    ["states.", Match.anyValue(), ".amazonaws.com"],
                  ],
                },
              },
            },
          ],
        },
      })
    );
```

```
    // Fully assert on the state machine's IAM role with matchers.
    template.hasResourceProperties(
      "AWS::IAM::Role",
      Match.objectEquals({
        AssumeRolePolicyDocument: {
          Version: "2012-10-17",		 	 	 
          Statement: [
            {
              Action: "sts:AssumeRole",
              Effect: "Allow",
              Principal: {
                Service: {
                  "Fn::Join": [
                    "",
                    ["states.", Match.anyValue(), ".amazonaws.com"],
                  ],
                },
              },
            },
          ],
        },
      })
    );
```

```
from aws_cdk.assertions import Match

    # Fully assert on the state machine's IAM role with matchers.
    template.has_resource_properties(
        "AWS::IAM::Role",
        Match.object_equals(
            {
                "AssumeRolePolicyDocument": {
                    "Version": "2012-10-17",		 	 	 
                    "Statement": [
                        {
                            "Action": "sts:AssumeRole",
                            "Effect": "Allow",
                            "Principal": {
                                "Service": {
                                    "Fn::Join": [
                                        "",
                                        [
                                            "states.",
                                            Match.any_value(),
                                            ".amazonaws.com",
                                        ],
                                    ],
                                },
                            },
                        },
                    ],
                },
            }
        ),
    )
```

```
        // Fully assert on the state machine's IAM role with matchers.
        template.hasResourceProperties("AWS::IAM::Role", Match.objectEquals(
                Collections.singletonMap("AssumeRolePolicyDocument", Map.of(
                        "Version", "2012-10-17",		 	 	 
                        "Statement", Collections.singletonList(Map.of(
                                "Action", "sts:AssumeRole",
                                "Effect", "Allow",
                                "Principal", Collections.singletonMap(
                                        "Service", Collections.singletonMap(
                                                "Fn::Join", Arrays.asList(
                                                        "",
                                                        Arrays.asList("states.", Match.anyValue(), ".amazonaws.com")
                                                )
                                        )
                                )
                        ))
                ))
        ));
```

```
            // Fully assert on the state machine's IAM role with matchers.
            template.HasResource("AWS::IAM::Role", Match.ObjectEquals(new ObjectDict
            {
                { "AssumeRolePolicyDocument", new ObjectDict
                    {
                        { "Version", "2012-10-17"		 	 	  },
                        { "Action", "sts:AssumeRole" },
                        { "Principal", new ObjectDict
                            {
                                { "Version", "2012-10-17"		 	 	  },
                                { "Statement", new object[]
                                    {
                                        new ObjectDict {
                                            { "Action", "sts:AssumeRole" },
                                            { "Effect", "Allow" },
                                            { "Principal", new ObjectDict
                                                {
                                                    { "Service", new ObjectDict
                                                        {
                                                            { "", new object[]
                                                                { "states", Match.AnyValue(), ".amazonaws.com" }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }));
```
許多 CloudFormation 資源包含以字串表示的序列化 JSON 物件。`Match.serializedJson()` 配對器可用來比對此 JSON 內的屬性。  
例如，Step Functions 狀態機器是使用 JSON 型 [Amazon States Language](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-amazon-states-language.html) 中的字串來定義。我們將使用 來`Match.serializedJson()`確保初始狀態是唯一的步驟。同樣地，我們將使用巢狀比對程式，將不同類型的比對套用至物件的不同部分。  

**Example**  

```
    // Assert on the state machine's definition with the Match.serializedJson()
    // matcher.
    template.hasResourceProperties("AWS::StepFunctions::StateMachine", {
      DefinitionString: Match.serializedJson(
        // Match.objectEquals() is used implicitly, but we use it explicitly
        // here for extra clarity.
        Match.objectEquals({
          StartAt: "StartState",
          States: {
            StartState: {
              Type: "Pass",
              End: true,
              // Make sure this state doesn't provide a next state -- we can't
              // provide both Next and set End to true.
              Next: Match.absent(),
            },
          },
        })
      ),
    });
```

```
    // Assert on the state machine's definition with the Match.serializedJson()
    // matcher.
    template.hasResourceProperties("AWS::StepFunctions::StateMachine", {
      DefinitionString: Match.serializedJson(
        // Match.objectEquals() is used implicitly, but we use it explicitly
        // here for extra clarity.
        Match.objectEquals({
          StartAt: "StartState",
          States: {
            StartState: {
              Type: "Pass",
              End: true,
              // Make sure this state doesn't provide a next state -- we can't
              // provide both Next and set End to true.
              Next: Match.absent(),
            },
          },
        })
      ),
    });
```

```
    # Assert on the state machine's definition with the serialized_json matcher.
    template.has_resource_properties(
        "AWS::StepFunctions::StateMachine",
        {
            "DefinitionString": Match.serialized_json(
                # Match.object_equals() is the default, but specify it here for clarity
                Match.object_equals(
                    {
                        "StartAt": "StartState",
                        "States": {
                            "StartState": {
                                "Type": "Pass",
                                "End": True,
                                # Make sure this state doesn't provide a next state --
                                # we can't provide both Next and set End to true.
                                "Next": Match.absent(),
                            },
                        },
                    }
                )
            ),
        },
    )
```

```
        // Assert on the state machine's definition with the Match.serializedJson() matcher.
        template.hasResourceProperties("AWS::StepFunctions::StateMachine", Collections.singletonMap(
                "DefinitionString", Match.serializedJson(
                        // Match.objectEquals() is used implicitly, but we use it explicitly here for extra clarity.
                        Match.objectEquals(Map.of(
                                "StartAt", "StartState",
                                "States", Collections.singletonMap(
                                        "StartState", Map.of(
                                                "Type", "Pass",
                                                "End", true,
                                                // Make sure this state doesn't provide a next state -- we can't provide
                                                // both Next and set End to true.
                                                "Next", Match.absent()
                                        )
                                )
                        ))
                )
        ));
```

```
            // Assert on the state machine's definition with the Match.serializedJson() matcher
            template.HasResourceProperties("AWS::StepFunctions::StateMachine", new ObjectDict
            {
                { "DefinitionString", Match.SerializedJson(
                    // Match.objectEquals() is used implicitly, but we use it explicitly here for extra clarity.
                    Match.ObjectEquals(new ObjectDict {
                        { "StartAt", "StartState" },
                        { "States", new ObjectDict
                        {
                            { "StartState", new ObjectDict {
                                { "Type", "Pass" },
                                { "End", "True" },
                                // Make sure this state doesn't provide a next state -- we can't provide
                                // both Next and set End to true.
                                { "Next", Match.Absent() }
                            }}
                        }}
                    })
                )}});
```<a name="testing-fine-grained-capture"></a>

 **擷取**   
測試屬性通常很實用，以確保它們遵循特定格式，或具有與另一個屬性相同的值，而不需要事先知道它們的確切值。`assertions` 模組在其` [Capture](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.assertions.Capture.html) `類別中提供此功能。  
透過指定`Capture`執行個體來取代 中的值`hasResourceProperties`，該值會保留在 `Capture` 物件中。實際擷取的值可以使用物件`as`的方法擷取，包括 `asNumber()`、 `asString()`和 `asObject`，並接受測試。使用 `Capture`搭配配對器來指定要在資源屬性中擷取之值的確切位置，包括序列化 JSON 屬性。  
下列範例會測試 ，以確保狀態機器的啟動狀態具有以 開頭的名稱`Start`。它也會測試此狀態是否存在於機器中的狀態清單中。  

**Example**  

```
    // Capture some data from the state machine's definition.
    const startAtCapture = new Capture();
    const statesCapture = new Capture();
    template.hasResourceProperties("AWS::StepFunctions::StateMachine", {
      DefinitionString: Match.serializedJson(
        Match.objectLike({
          StartAt: startAtCapture,
          States: statesCapture,
        })
      ),
    });

    // Assert that the start state starts with "Start".
    expect(startAtCapture.asString()).toEqual(expect.stringMatching(/^Start/));

    // Assert that the start state actually exists in the states object of the
    // state machine definition.
    expect(statesCapture.asObject()).toHaveProperty(startAtCapture.asString());
```

```
    // Capture some data from the state machine's definition.
    const startAtCapture = new Capture();
    const statesCapture = new Capture();
    template.hasResourceProperties("AWS::StepFunctions::StateMachine", {
      DefinitionString: Match.serializedJson(
        Match.objectLike({
          StartAt: startAtCapture,
          States: statesCapture,
        })
      ),
    });

    // Assert that the start state starts with "Start".
    expect(startAtCapture.asString()).toEqual(expect.stringMatching(/^Start/));

    // Assert that the start state actually exists in the states object of the
    // state machine definition.
    expect(statesCapture.asObject()).toHaveProperty(startAtCapture.asString());
```

```
import re

    from aws_cdk.assertions import Capture

    # ...

    # Capture some data from the state machine's definition.
    start_at_capture = Capture()
    states_capture = Capture()
    template.has_resource_properties(
        "AWS::StepFunctions::StateMachine",
        {
            "DefinitionString": Match.serialized_json(
                Match.object_like(
                    {
                        "StartAt": start_at_capture,
                        "States": states_capture,
                    }
                )
            ),
        },
    )

    # Assert that the start state starts with "Start".
    assert re.match("^Start", start_at_capture.as_string())

    # Assert that the start state actually exists in the states object of the
    # state machine definition.
    assert start_at_capture.as_string() in states_capture.as_object()
```

```
        // Capture some data from the state machine's definition.
        final Capture startAtCapture = new Capture();
        final Capture statesCapture = new Capture();
        template.hasResourceProperties("AWS::StepFunctions::StateMachine", Collections.singletonMap(
                "DefinitionString", Match.serializedJson(
                        Match.objectLike(Map.of(
                                "StartAt", startAtCapture,
                                "States", statesCapture
                        ))
                )
        ));

        // Assert that the start state starts with "Start".
        assertThat(startAtCapture.asString()).matches("^Start.+");

        // Assert that the start state actually exists in the states object of the state machine definition.
        assertThat(statesCapture.asObject()).containsKey(startAtCapture.asString());
```

```
            // Capture some data from the state machine's definition.
            var startAtCapture = new Capture();
            var statesCapture = new Capture();
            template.HasResourceProperties("AWS::StepFunctions::StateMachine", new ObjectDict
            {
                { "DefinitionString", Match.SerializedJson(
                    new ObjectDict
                    {
                        { "StartAt", startAtCapture },
                        { "States", statesCapture }
                    }
                )}
            });

            Assert.IsTrue(startAtCapture.ToString().StartsWith("Start"));
            Assert.IsTrue(statesCapture.AsObject().ContainsKey(startAtCapture.ToString()));
```

## 快照測試
<a name="testing-snapshot"></a>

在*快照測試*中，您可以將整個合成的 CloudFormation 範本與先前儲存的基準 （通常稱為「主要」) 範本進行比較。與精細的聲明不同，快照測試在擷取迴歸時沒有用。這是因為快照測試適用於整個範本，除了程式碼變更之外，還可能導致合成結果小 （或not-so-small的差異。這些變更甚至不會影響您的部署，但仍會導致快照測試失敗。

例如，您可以更新 CDK 建構以納入新的最佳實務，這可能會導致合成資源或組織方式的變更。或者，您可以將 CDK Toolkit 更新為報告其他中繼資料的版本。內容值的變更也會影響合成的範本。

不過，只要您持續保留可能影響合成範本的所有其他因素，快照測試對於重構很有幫助。如果您所做的變更無意中變更了範本，您會立即知道。如果變更是刻意的，只要接受新範本做為基準即可。

例如，如果我們有此`DeadLetterQueue`建構：

**Example**  

```
export class DeadLetterQueue extends sqs.Queue {
  public readonly messagesInQueueAlarm: cloudwatch.IAlarm;

  constructor(scope: Construct, id: string) {
    super(scope, id);

    // Add the alarm
    this.messagesInQueueAlarm = new cloudwatch.Alarm(this, 'Alarm', {
      alarmDescription: 'There are messages in the Dead Letter Queue',
      evaluationPeriods: 1,
      threshold: 1,
      metric: this.metricApproximateNumberOfMessagesVisible(),
    });
  }
}
```

```
class DeadLetterQueue extends sqs.Queue {

  constructor(scope, id) {
    super(scope, id);

    // Add the alarm
    this.messagesInQueueAlarm = new cloudwatch.Alarm(this, 'Alarm', {
      alarmDescription: 'There are messages in the Dead Letter Queue',
      evaluationPeriods: 1,
      threshold: 1,
      metric: this.metricApproximateNumberOfMessagesVisible(),
    });
  }
}

module.exports = { DeadLetterQueue }
```

```
class DeadLetterQueue(sqs.Queue):
    def __init__(self, scope: Construct, id: str):
        super().__init__(scope, id)

        self.messages_in_queue_alarm = cloudwatch.Alarm(
            self,
            "Alarm",
            alarm_description="There are messages in the Dead Letter Queue.",
            evaluation_periods=1,
            threshold=1,
            metric=self.metric_approximate_number_of_messages_visible(),
        )
```

```
public class DeadLetterQueue extends Queue {
    private final IAlarm messagesInQueueAlarm;

    public DeadLetterQueue(@NotNull Construct scope, @NotNull String id) {
        super(scope, id);

        this.messagesInQueueAlarm = Alarm.Builder.create(this, "Alarm")
                .alarmDescription("There are messages in the Dead Letter Queue.")
                .evaluationPeriods(1)
                .threshold(1)
                .metric(this.metricApproximateNumberOfMessagesVisible())
                .build();
    }

    public IAlarm getMessagesInQueueAlarm() {
        return messagesInQueueAlarm;
    }
}
```

```
namespace AwsCdkAssertionSamples
{
    public class DeadLetterQueue : Queue
    {
        public IAlarm messagesInQueueAlarm;

        public DeadLetterQueue(Construct scope, string id) : base(scope, id)
        {
            messagesInQueueAlarm = new Alarm(this, "Alarm", new AlarmProps
            {
                AlarmDescription = "There are messages in the Dead Letter Queue.",
                EvaluationPeriods = 1,
                Threshold = 1,
                Metric = this.MetricApproximateNumberOfMessagesVisible()
            });
        }
    }
}
```

我們可以如下所示進行測試：

**Example**  

```
import { Match, Template } from "aws-cdk-lib/assertions";
import * as cdk from "aws-cdk-lib";
import { DeadLetterQueue } from "../lib/dead-letter-queue";

describe("DeadLetterQueue", () => {
  test("matches the snapshot", () => {
    const stack = new cdk.Stack();
    new DeadLetterQueue(stack, "DeadLetterQueue");

    const template = Template.fromStack(stack);
    expect(template.toJSON()).toMatchSnapshot();
  });
});
```

```
const { Match, Template } = require("aws-cdk-lib/assertions");
const cdk = require("aws-cdk-lib");
const { DeadLetterQueue } = require("../lib/dead-letter-queue");

describe("DeadLetterQueue", () => {
  test("matches the snapshot", () => {
    const stack = new cdk.Stack();
    new DeadLetterQueue(stack, "DeadLetterQueue");

    const template = Template.fromStack(stack);
    expect(template.toJSON()).toMatchSnapshot();
  });
});
```

```
import aws_cdk_lib as cdk
from aws_cdk_lib.assertions import Match, Template

from app.dead_letter_queue import DeadLetterQueue

def snapshot_test():
    stack = cdk.Stack()
    DeadLetterQueue(stack, "DeadLetterQueue")

    template = Template.from_stack(stack)
    assert template.to_json() == snapshot
```

```
package software.amazon.samples.awscdkassertionssamples;

import org.junit.jupiter.api.Test;
import au.com.origin.snapshots.Expect;
import software.amazon.awscdk.assertions.Match;
import software.amazon.awscdk.assertions.Template;
import software.amazon.awscdk.Stack;

import java.util.Collections;
import java.util.Map;

public class DeadLetterQueueTest {
    @Test
    public void snapshotTest() {
        final Stack stack = new Stack();
        new DeadLetterQueue(stack, "DeadLetterQueue");

        final Template template = Template.fromStack(stack);
        expect.toMatchSnapshot(template.toJSON());
    }
}
```

```
using Microsoft.VisualStudio.TestTools.UnitTesting;

using Amazon.CDK;
using Amazon.CDK.Assertions;
using AwsCdkAssertionSamples;

using ObjectDict = System.Collections.Generic.Dictionary<string, object>;
using StringDict = System.Collections.Generic.Dictionary<string, string>;

namespace TestProject1
{
    [TestClass]
    public class StateMachineStackTest

    [TestClass]
    public class DeadLetterQueueTest
    {
    [TestMethod]
        public void SnapshotTest()
        {
            var stack = new Stack();
            new DeadLetterQueue(stack, "DeadLetterQueue");

            var template = Template.FromStack(stack);

            return Verifier.Verify(template.ToJSON());
        }
    }
}
```

## 測試提示
<a name="testing-tips"></a>

請記住，只要測試程式碼，您的測試就會持續運作，而且會像往常一樣進行讀取和修改。因此，需要一些時間來考慮如何最好地撰寫它們。

請勿複製和貼上設定行或常見聲明。反之，請將此邏輯重構為固定設備或協助程式函數。使用良好名稱來反映每個測試實際測試的內容。

請勿嘗試在一次測試中執行太多操作。測試最好只測試一個行為。如果您不小心破壞了該行為，則只會有一個測試失敗，而且測試的名稱應該告訴您失敗了什麼。不過，這更適合努力；有時您會無可避免地 （或不小心） 寫入測試，以測試多個行為。快照測試是基於我們已說明的原因，特別是容易發生此問題，因此請謹慎使用。

# 使用 SAM CLI AWS 在本機測試和建置 AWS CDK 應用程式
<a name="testing-locally"></a>

您可以使用 AWS SAM CLI 在本機測試和建置使用 AWS 雲端開發套件 (AWS CDK) 定義的無伺服器應用程式。由於 AWS SAM CLI 可在 AWS CDK 專案結構內運作，因此您仍然可以使用 [AWS CDK CLI 參考](cli.md)來建立、修改和部署 AWS CDK 應用程式。

如需使用 AWS SAM [AWS 的詳細資訊，請參閱《無伺服器應用程式模型開發人員指南》中的 SAM 入門](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-getting-started.html)。 * AWS *

**Topics**
+ [本機測試入門](testing-locally-getting-started.md)
+ [使用 SAM AWS 本機測試 AWS CDK 應用程式](testing-locally-with-sam-cli.md)
+ [使用 SAM AWS 建置 AWS CDK 應用程式](testing-locally-build-with-sam-cli.md)

# 本機測試入門
<a name="testing-locally-getting-started"></a>

本主題說明搭配 AWS CDK 應用程式使用 AWS SAM CLI 所需的內容，並提供建置和本機測試簡單 AWS CDK 應用程式的指示。

## 先決條件
<a name="testing-locally-getting-started-prerequisites"></a>

若要在本機測試，您必須安裝 AWS SAM CLI。如需安裝說明[，請參閱安裝 AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/getting_started.html)。

## 建立和本機測試 AWS CDK 應用程式
<a name="testing-locally-getting-started-tutorial"></a>

若要使用 SAM AWS CLI 在本機測試 AWS CDK 應用程式，您必須擁有包含 Lambda 函數的 AWS CDK 應用程式。使用下列步驟建立具有 Lambda 函數的基本 AWS CDK 應用程式。如需詳細資訊，請參閱《雲端開發套件 (CDK) 開發人員指南》中的[使用 AWS CDK 建立無伺服器應用程式](https://docs.aws.amazon.com/cdk/latest/guide/serverless_example.html)。 * AWS AWS *<a name="testing-locally-getting-started-tutorial-init"></a>

 **步驟 1：建立 AWS CDK 應用程式**   
在本教學課程中，初始化使用 TypeScript 的 AWS CDK 應用程式。  
要執行的命令：  

```
$ mkdir cdk-sam-example
$ cd cdk-sam-example
$ cdk init app --language typescript
```<a name="testing-locally-getting-started-tutorial-lambda"></a>

 **步驟 2：將 Lambda 函數新增至您的應用程式**   
使用`lib/cdk-sam-example-stack.ts`下列項目取代 中的程式碼：  

```
import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as lambda from 'aws-cdk-lib/aws-lambda';

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

    new lambda.Function(this, 'MyFunction', {
      runtime: lambda.Runtime.PYTHON_3_12,
      handler: 'app.lambda_handler',
      code: lambda.Code.fromAsset('./my_function'),
    });
  }
}
```<a name="testing-locally-getting-started-tutorial-code"></a>

 **步驟 3：新增您的 Lambda 函數程式碼**   
建立名為 `my_function` 的目錄。在該目錄中，建立名為 `app.py` 的檔案。  
要執行的命令：  

**Example**  

```
$ mkdir my_function
$ cd my_function
$ touch app.py
```

```
$ mkdir my_function
$ cd my_function
$ type nul > app.py
```

```
$ mkdir my_function
$ cd my_function
$ New-Item -Path "app.py”
```
為 `app.py` 添加以下程式碼：

```
def lambda_handler(event, context):
    return "Hello from SAM and the CDK!"
```<a name="testing-locally-getting-started-tutorial-function"></a>

 **步驟 4：測試您的 Lambda 函數**   
您可以使用 AWS SAM CLI 在本機叫用您在 AWS CDK 應用程式中定義的 Lambda 函數。若要這樣做，您需要函數建構識別碼和合成 AWS CloudFormation 範本的路徑。  
執行下列命令以返回 `lib`目錄：  

```
$  cd ..
```
 **要執行的命令：**  

```
$  cdk synth --no-staging
```

```
$  sam local invoke MyFunction --no-event -t ./cdk.out/CdkSamExampleStack.template.json
```
 **輸出範例：**  

```
Invoking app.lambda_handler (python3.9)

START RequestId: 5434c093-7182-4012-9b06-635011cac4f2 Version: $LATEST
"Hello from SAM and the CDK!"
END RequestId: 5434c093-7182-4012-9b06-635011cac4f2
REPORT RequestId: 5434c093-7182-4012-9b06-635011cac4f2	Init Duration: 0.32 ms	Duration: 177.47 ms	Billed Duration: 178 ms	Memory Size: 128 MB	Max Memory Used: 128 MB
```

# 使用 SAM AWS 本機測試 AWS CDK 應用程式
<a name="testing-locally-with-sam-cli"></a>

您可以使用 AWS SAM CLI，從 AWS CDK 應用程式的專案根目錄執行下列命令，在本機測試您的 AWS CDK 應用程式：
+  ` [sam local invoke](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-local-invoke.html) ` 
+  ` [sam local start-api](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-local-start-api.html) ` 
+  ` [sam local start-lambda](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-local-start-lambda.html) ` 

在使用 AWS CDK 應用程式執行任何`sam local`命令之前，您必須執行 `cdk synth`。

執行時`sam local invoke`，您需要要叫用的函數建構識別符，以及合成 AWS CloudFormation 範本的路徑。如果您的應用程式使用巢狀堆疊，為了解決命名衝突，您也需要定義函數的堆疊名稱。

 **用途**   

```
# Invoke the function FUNCTION_IDENTIFIER declared in the stack STACK_NAME
$  sam local invoke <OPTIONS> <STACK_NAME/FUNCTION_IDENTIFIER>

# Start all APIs declared in the AWS CDK application
$  sam local start-api -t <./cdk.out/CdkSamExampleStack.template.json> <OPTIONS>

# Start a local endpoint that emulates AWS Lambda
$  sam local start-lambda -t <./cdk.out/CdkSamExampleStack.template.json> <OPTIONS>
```

## 範例
<a name="testing-cdk-applications-examples"></a>

請考慮使用下列範例宣告的堆疊和函數：

```
app = new HelloCdkStack(app, "HelloCdkStack",
   ...
)
class HelloCdkStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    ...
    new lambda.Function(this, 'MyFunction', {
        ...
    });

    new HelloCdkNestedStack(this, 'HelloNestedStack' ,{
        ...
    });
  }
}

class HelloCdkNestedStack extends cdk.NestedStack {
  constructor(scope: Construct, id: string, props?: cdk.NestedStackProps) {
    ...
    new lambda.Function(this, 'MyFunction', {
        ...
    });
    new lambda.Function(this, 'MyNestedFunction', {
        ...
    });
  }
}
```

下列命令會在本機叫用上述範例中定義的 Lambda 函數：

```
# Invoke MyFunction from the HelloCdkStack
$ sam local invoke -t <./cdk.out/HelloCdkStack.template.json> <MyFunction>
```

```
# Invoke MyNestedFunction from the HelloCdkNestedStack
$ sam local invoke -t <./cdk.out/HelloCdkStack.template.json> <MyNestedFunction>
```

```
# Invoke MyFunction from the HelloCdkNestedStack
$ sam local invoke -t <./cdk.out/HelloCdkStack.template.json> <HelloNestedStack/MyFunction>
```

# 使用 SAM AWS 建置 AWS CDK 應用程式
<a name="testing-locally-build-with-sam-cli"></a>

 AWS SAM CLI 支援使用 建置 AWS CDK 應用程式中定義的 Lambda 函數和層` [sam build](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-build.html) `。

對於使用 zip 成品的 Lambda 函數，請在執行`sam local`命令`cdk synth`之前執行 。 `sam build` 不需要。

如果您的 AWS CDK 應用程式使用 函數搭配 映像類型，請在執行`sam local`命令`sam build`之前執行 `cdk synth` ，然後執行 。當您執行 時`sam build`， AWS SAM 不會建置使用執行時間特定建構的 Lambda 函數或層，例如 ` [NodejsFunction](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_nodejs.NodejsFunction.html) `。 `sam build` 不支援[綁定資產](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.BundlingOptions.html)。

## 範例
<a name="testing-locally-build-with-sam-cli-examples"></a>

從 AWS CDK 專案根目錄執行下列命令會建置應用程式。

```
$ sam build -t <./cdk.out/CdkSamExampleStack.template.json>
```