

Ceci est le guide du développeur du AWS CDK v2. L'ancien CDK v1 est entré en maintenance le 1er juin 2022 et a pris fin le 1er juin 2023.

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

# Testez les AWS applications CDK
<a name="testing"></a>

Avec le AWS CDK, votre infrastructure peut être aussi testable que n'importe quel autre code que vous écrivez. Vous pouvez effectuer des tests dans le cloud et localement. Cette rubrique explique comment effectuer des tests dans le cloud. Pour obtenir des conseils sur les tests locaux, voir [Tester localement et créer des applications AWS CDK avec la CLI AWS SAM](testing-locally.md). [L'approche standard pour tester les applications AWS CDK utilise le module d'[assertions](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.assertions-readme.html) du AWS CDK et des frameworks de test populaires tels que [Jest](https://jestjs.io/) pour et/ou JavaScript Pytest pour TypeScript Python.](https://docs.pytest.org/en/6.2.x/)

Il existe deux catégories de tests que vous pouvez écrire pour les applications AWS CDK.
+  **Des assertions détaillées testent des** aspects spécifiques du AWS CloudFormation modèle généré, tels que « cette ressource possède cette propriété avec cette valeur ». Ces tests permettent de détecter des régressions. Ils sont également utiles lorsque vous développez de nouvelles fonctionnalités à l'aide du développement piloté par les tests. (Vous pouvez d'abord écrire un test, puis le réussir en écrivant une implémentation correcte.) Les assertions précises sont les tests les plus fréquemment utilisés.
+  **Les tests instantanés** testent le AWS CloudFormation modèle synthétisé par rapport à un modèle de référence précédemment stocké. Les tests instantanés vous permettent de refactoriser librement, car vous pouvez être sûr que le code refactorisé fonctionne exactement de la même manière que le code original. Si les modifications étaient intentionnelles, vous pouvez accepter une nouvelle référence pour les futurs tests. Cependant, les mises à niveau du CDK peuvent également entraîner la modification des modèles synthétisés. Vous ne pouvez donc pas vous fier uniquement aux instantanés pour vous assurer que votre implémentation est correcte.

**Note**  
Les versions complètes TypeScript des applications Python et Java utilisées comme exemples dans cette rubrique sont [disponibles sur GitHub](https://github.com/cdklabs/aws-cdk-testing-examples/).

## Prise en main
<a name="testing-getting-started"></a>

Pour illustrer comment écrire ces tests, nous allons créer une pile contenant une machine à états AWS Step Functions et une fonction AWS Lambda. La fonction Lambda est abonnée à une rubrique Amazon SNS et transmet simplement le message à la machine d'état.

Tout d'abord, créez un projet d'application CDK vide à l'aide du CDK Toolkit et en installant les bibliothèques dont nous aurons besoin. Les constructions que nous utiliserons se trouvent toutes dans le package CDK principal, qui est une dépendance par défaut dans les projets créés avec le CDK Toolkit. Cependant, vous devez installer votre framework de test.

**Example**  

```
$ mkdir state-machine && cd state-machine
cdk init --language=typescript
npm install --save-dev jest @types/jest
```
Créez un répertoire pour vos tests.  

```
$ mkdir test
```
Modifiez les projets `package.json` pour indiquer à NPM comment exécuter Jest et pour indiquer à Jest quels types de fichiers collecter. Les modifications nécessaires sont les suivantes.  
+ Ajouter une nouvelle `test` clé à la `scripts` section
+ Ajoutez Jest et ses types à la section `devDependencies`
+ Ajouter une nouvelle clé `jest` de niveau supérieur avec une déclaration `moduleFileExtensions`
Ces modifications sont présentées dans le schéma suivant. Placez le nouveau texte à l'endroit indiqué dans`package.json`. Les espaces réservés «... » indiquent les parties existantes du fichier qui ne doivent pas être modifiées.  

```
{
  ...
  "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
```
Créez un répertoire pour vos tests.  

```
$ mkdir test
```
Modifiez les projets `package.json` pour indiquer à NPM comment exécuter Jest et pour indiquer à Jest quels types de fichiers collecter. Les modifications nécessaires sont les suivantes.  
+ Ajouter une nouvelle `test` clé à la `scripts` section
+ Ajoutez Jest à la section `devDependencies`
+ Ajouter une nouvelle clé `jest` de niveau supérieur avec une déclaration `moduleFileExtensions`
Ces modifications sont présentées dans le schéma suivant. Placez le nouveau texte à l'endroit indiqué dans`package.json`. Les espaces réservés «... » indiquent les parties existantes du fichier qui ne doivent pas être modifiées.  

```
{
  ...
  "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
```
Ouvrez le projet dans l'IDE Java de votre choix. (Dans Eclipse, utilisez **Fichier** > **Importer** > Projets Maven existants.)

```
$ mkdir state-machine && cd-state-machine
$ cdk init --language=csharp
```
Ouvrez `src\StateMachine.sln` dans Visual Studio.  
Cliquez avec le bouton droit sur la solution dans l'Explorateur de solutions et choisissez **Ajouter** > **Nouveau projet**. Recherchez MSTest C\$1 et ajoutez un **projet de MSTest test** pour C\$1. (Le nom par défaut TestProject « 1 » convient.)  
Cliquez avec le bouton droit de la souris `TestProject1` et choisissez **Ajouter** > **Référence** du `StateMachine` projet, puis ajoutez le projet comme référence.

## La pile d'exemples
<a name="testing-app"></a>

Voici la pile qui sera testée dans cette rubrique. Comme nous l'avons décrit précédemment, il contient une fonction Lambda et une machine d'état Step Functions, et accepte une ou plusieurs rubriques Amazon SNS. La fonction Lambda est abonnée aux rubriques Amazon SNS et les transmet à la machine à états.

Vous n'avez rien à faire de spécial pour rendre l'application testable. En fait, cette pile de CDK n'est pas différente des autres exemples de piles présentés dans ce guide.

**Example**  
Entrez le code suivant dans `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);
    }
  }
}
```
Entrez le code suivant dans `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 }
```
Entrez le code suivant dans `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);
            }

        }
    }
}
```

Nous allons modifier le point d'entrée principal de l'application afin de ne pas réellement instancier notre stack. Nous ne voulons pas le déployer accidentellement. Nos tests créeront une application et une instance de la pile à des fins de test. Cette tactique est utile lorsqu'elle est associée au développement piloté par les tests : assurez-vous que la pile passe tous les tests avant d'activer le déploiement.

**Example**  
Dans `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.
```
Dans `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.
```
Dans `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();
        }
    }
}
```

## La fonction Lambda
<a name="testing-lambda"></a>

Notre exemple de pile inclut une fonction Lambda qui démarre notre machine à états. Nous devons fournir le code source de cette fonction afin que le CDK puisse la regrouper et la déployer dans le cadre de la création de la ressource de fonction Lambda.
+ Créez le dossier `start-state-machine` dans le répertoire principal de l'application.
+ Dans ce dossier, créez au moins un fichier. Par exemple, vous pouvez enregistrer le code suivant dans`start-state-machines/index.js`.

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

  Cependant, n'importe quel fichier fonctionnera, car nous ne déploierons pas réellement la pile.

## Exécution de tests
<a name="testing-running-tests"></a>

À titre de référence, voici les commandes que vous utilisez pour exécuter des tests dans votre application AWS CDK. Il s'agit des mêmes commandes que vous utiliseriez pour exécuter les tests dans n'importe quel projet utilisant le même framework de test. Pour les langages qui nécessitent une étape de compilation, incluez-la pour vous assurer que vos tests ont été compilés.

**Example**  

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

```
$ npm test
```

```
$ python -m pytest
```

```
$ mvn compile && mvn test
```
Créez votre solution (F6) pour découvrir les tests, puis exécutez-les (**Test** > **Exécuter tous les tests**). Pour choisir les tests à exécuter, ouvrez l'Explorateur de tests (**Test** **> Explorateur** de tests).  
Ou:  

```
$ dotnet test src
```

## Assertions fines
<a name="testing-fine-grained"></a>

La première étape pour tester une pile avec des assertions détaillées consiste à synthétiser la pile, car nous écrivons des assertions par rapport au modèle généré. AWS CloudFormation 

Nous `StateMachineStackStack` exigeons que nous lui transmettions le sujet Amazon SNS à transmettre à la machine d'état. Dans notre test, nous allons donc créer une pile séparée pour contenir le sujet.

Normalement, lorsque vous écrivez une application CDK, vous pouvez sous-classer `Stack` et instancier la rubrique Amazon SNS dans le constructeur de la pile. Dans notre test, nous instancions `Stack` directement, puis nous transmettons cette pile comme scope, en `Topic` l'attachant à la pile. C'est équivalent sur le plan fonctionnel et moins verbeux. Cela permet également de rendre les piles utilisées uniquement dans les tests « différentes » des piles que vous avez l'intention de déployer.

**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
        }
    }
}
```

Nous pouvons maintenant affirmer que la fonction Lambda et l'abonnement Amazon SNS ont été créés.

**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);
```

Notre test de fonction Lambda affirme que deux propriétés particulières de la ressource fonctionnelle ont des valeurs spécifiques. Par défaut, la `hasResourceProperties` méthode effectue une correspondance partielle sur les propriétés de la ressource telles qu'elles sont indiquées dans le CloudFormation modèle synthétisé. Ce test nécessite que les propriétés fournies existent et aient les valeurs spécifiées, mais la ressource peut également avoir d'autres propriétés, qui ne sont pas testées.

Notre assertion Amazon SNS affirme que le modèle synthétisé contient un abonnement, mais rien sur l'abonnement lui-même. Nous avons inclus cette assertion principalement pour illustrer comment affirmer le nombre de ressources. La `Template` classe propose des méthodes plus spécifiques pour écrire des assertions par rapport aux `Mapping` sections `Resources``Outputs`, et du CloudFormation modèle.<a name="testing-fine-grained-matchers"></a>

 **Allumeurs**   
Le comportement de correspondance partielle par défaut de `hasResourceProperties` peut être modifié à l'aide *des matchers* de la ` [Match](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.assertions.Match.html#methods) ` classe.  
Les matchers vont de indulgent (`Match.anyValue`) à strict (`Match.objectEquals`). Ils peuvent être imbriqués pour appliquer différentes méthodes de correspondance aux différentes parties des propriétés des ressources. En utilisant `Match.objectEquals` et `Match.anyValue` ensemble, par exemple, nous pouvons tester le rôle IAM de la machine à états de manière plus complète, sans exiger de valeurs spécifiques pour les propriétés susceptibles de changer.  

**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" }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }));
```
De nombreuses CloudFormation ressources incluent des objets JSON sérialisés représentés sous forme de chaînes. Le `Match.serializedJson()` matcher peut être utilisé pour faire correspondre les propriétés de ce JSON.  
Par exemple, les machines à états Step Functions sont définies à l'aide d'une chaîne dans le langage [Amazon States](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-amazon-states-language.html) Language basé sur JSON. Nous utiliserons `Match.serializedJson()` pour nous assurer que notre état initial est la seule étape. Encore une fois, nous utiliserons des matchers imbriqués pour appliquer différents types de correspondance aux différentes parties de l'objet.  

**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>

 **Capture**   
Il est souvent utile de tester les propriétés pour s'assurer qu'elles suivent des formats spécifiques ou qu'elles ont la même valeur qu'une autre propriété, sans avoir besoin de connaître leurs valeurs exactes à l'avance. Le `assertions` module fournit cette fonctionnalité dans sa ` [Capture](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.assertions.Capture.html) ` classe.  
En spécifiant une `Capture` instance à la place d'une valeur in`hasResourceProperties`, cette valeur est conservée dans l'`Capture`objet. La valeur capturée réelle peut être récupérée à l'aide `as` des méthodes de l'objet `asNumber()``asString()`, notamment`asObject`, et soumise à un test. À utiliser `Capture` avec un comparateur pour spécifier l'emplacement exact de la valeur à capturer dans les propriétés de la ressource, y compris les propriétés JSON sérialisées.  
L'exemple suivant teste pour s'assurer que l'état de départ de notre machine à états porte un nom commençant par`Start`. Il vérifie également que cet état est présent dans la liste des états de la machine.  

**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()));
```

## Tests instantanés
<a name="testing-snapshot"></a>

Lors *des tests instantanés*, vous comparez l'intégralité du CloudFormation modèle synthétisé à un modèle de référence précédemment stocké (souvent appelé « modèle principal »). Contrairement aux assertions détaillées, les tests instantanés ne sont pas utiles pour détecter les régressions. Cela est dû au fait que les tests instantanés s'appliquent à l'ensemble du modèle et que d'autres éléments que les modifications de code peuvent entraîner de légères (ou not-so-small) différences dans les résultats de synthèse. Ces modifications n'affecteront peut-être même pas votre déploiement, mais elles entraîneront tout de même l'échec d'un test de capture instantanée.

Par exemple, vous pouvez mettre à jour une structure de CDK pour intégrer une nouvelle bonne pratique, ce qui peut entraîner des modifications des ressources synthétisées ou de la façon dont elles sont organisées. Vous pouvez également mettre à jour le kit d'outils CDK vers une version qui indique des métadonnées supplémentaires. Les modifications apportées aux valeurs de contexte peuvent également affecter le modèle synthétisé.

Les tests instantanés peuvent toutefois être d'une grande aide pour le refactoring, à condition de maintenir constants tous les autres facteurs susceptibles d'affecter le modèle synthétisé. Vous saurez immédiatement si une modification que vous avez apportée a involontairement modifié le modèle. Si le changement est intentionnel, il suffit d'accepter le nouveau modèle comme base de référence.

Par exemple, si nous avons cette `DeadLetterQueue` construction :

**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()
            });
        }
    }
}
```

Nous pouvons le tester comme ceci :

**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());
        }
    }
}
```

## Conseils pour les tests
<a name="testing-tips"></a>

N'oubliez pas que vos tests dureront aussi longtemps que le code qu'ils testent, et qu'ils seront lus et modifiés aussi souvent. Par conséquent, il vaut la peine de prendre un moment pour réfléchir à la meilleure façon de les écrire.

Ne copiez pas et ne collez pas de lignes de configuration ou d'assertions courantes. Refactorisez plutôt cette logique en accessoires ou en fonctions auxiliaires. Utilisez de bons noms qui reflètent ce que chaque test teste réellement.

N'essayez pas d'en faire trop en un seul test. De préférence, un test ne doit tester qu'un seul comportement. Si vous rompez accidentellement ce comportement, un seul test doit échouer, et le nom du test doit vous indiquer ce qui a échoué. Cependant, il s'agit plutôt d'un idéal à atteindre ; il arrive que vous écriviez inévitablement (ou par inadvertance) des tests qui testent plus d'un comportement. Pour les raisons que nous avons déjà décrites, les tests instantanés sont particulièrement sujets à ce problème. Utilisez-les donc avec parcimonie.

# Testez et créez localement des applications AWS CDK avec la CLI AWS SAM
<a name="testing-locally"></a>

Vous pouvez utiliser la CLI AWS SAM pour tester et créer localement des applications sans serveur définies à l'aide du AWS Cloud Development Kit (AWS CDK). Comme la CLI AWS SAM fonctionne au sein de la structure du projet AWS CDK, vous pouvez toujours utiliser la [référence de la AWS CLI CDK](cli.md) pour créer, modifier et déployer vos applications AWS CDK.

Pour plus de détails sur l'utilisation de AWS SAM, voir [Getting started with AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-getting-started.html) dans le *Guide du développeur du modèle d'application AWS sans serveur*.

**Topics**
+ [Commencer à tester localement](testing-locally-getting-started.md)
+ [Tester des applications AWS CDK en local avec SAM AWS](testing-locally-with-sam-cli.md)
+ [Création d'applications AWS CDK avec SAM AWS](testing-locally-build-with-sam-cli.md)

# Commencer à tester localement
<a name="testing-locally-getting-started"></a>

Cette rubrique décrit ce dont vous avez besoin pour utiliser la CLI AWS SAM avec des applications AWS CDK et fournit des instructions pour créer et tester localement une application AWS CDK simple.

## Prérequis
<a name="testing-locally-getting-started-prerequisites"></a>

Pour effectuer un test local, vous devez installer la CLI AWS SAM. Voir [Installer la CLI AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/getting_started.html) pour les instructions d'installation.

## Création et test local d'une application AWS CDK
<a name="testing-locally-getting-started-tutorial"></a>

Pour tester localement une application AWS CDK à l'aide de la CLI AWS SAM, vous devez disposer d'une application AWS CDK contenant une fonction Lambda. Suivez les étapes ci-dessous pour créer une application AWS CDK de base avec une fonction Lambda. Pour plus d'informations, consultez la section [Création d'une application sans serveur à l'aide du AWS CDK](https://docs.aws.amazon.com/cdk/latest/guide/serverless_example.html) dans le Guide du * AWS développeur du Cloud Development Kit (AWS CDK)*.<a name="testing-locally-getting-started-tutorial-init"></a>

 **Étape 1 : Création d'une application AWS CDK**   
Pour ce didacticiel, initialisez une application AWS CDK qui utilise. TypeScript  
Commande à exécuter :  

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

 **Étape 2 : ajouter une fonction Lambda à votre application**   
Remplacez le code dans `lib/cdk-sam-example-stack.ts` par ce qui suit :  

```
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>

 **Étape 3 : Ajoutez votre code de fonction Lambda**   
Créez un répertoire nommé `my_function`. Dans ce répertoire, créez un fichier nommé `app.py`.  
Commande à exécuter :  

**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”
```
Ajoutez le code suivant à `app.py`:

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

 **Étape 4 : Testez votre fonction Lambda**   
Vous pouvez utiliser la CLI AWS SAM pour appeler localement une fonction Lambda que vous définissez dans une application AWS CDK. Pour ce faire, vous avez besoin de l'identifiant de construction de la fonction et du chemin d'accès à votre AWS CloudFormation modèle synthétisé.  
Exécutez la commande suivante pour revenir au `lib` répertoire :  

```
$  cd ..
```
 **Commande à exécuter :**   

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

```
$  sam local invoke MyFunction --no-event -t ./cdk.out/CdkSamExampleStack.template.json
```
 **Exemple de sortie :**   

```
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
```

# Tester des applications AWS CDK en local avec SAM AWS
<a name="testing-locally-with-sam-cli"></a>

Vous pouvez utiliser la CLI AWS SAM pour tester localement vos applications AWS CDK en exécutant les commandes suivantes depuis le répertoire racine du projet de votre application 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) ` 

Avant d'exécuter l'une des `sam local` commandes avec une application AWS CDK, vous devez exécuter`cdk synth`.

Lors de l'exécution, `sam local invoke` vous avez besoin de l'identifiant de construction de la fonction que vous souhaitez invoquer et du chemin d'accès à votre AWS CloudFormation modèle synthétisé. Si votre application utilise des piles imbriquées, pour résoudre les conflits de noms, vous avez également besoin du nom de la pile dans laquelle la fonction est définie.

 **Utilisation**   

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

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

Envisagez d'utiliser des piles et des fonctions déclarées avec l'exemple suivant :

```
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', {
        ...
    });
  }
}
```

Les commandes suivantes appellent localement les fonctions Lambda définies dans l'exemple présenté ci-dessus :

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

# Création d'applications AWS CDK avec SAM AWS
<a name="testing-locally-build-with-sam-cli"></a>

La CLI AWS SAM permet de créer des fonctions et des couches Lambda définies dans votre application AWS CDK avec. ` [sam build](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-build.html) `

Pour les fonctions Lambda qui utilisent des artefacts zip, exécutez-les `cdk synth` avant d'exécuter des commandes. `sam local` `sam build`n'est pas obligatoire.

Si votre application AWS CDK utilise des fonctions de type image, exécutez-la `cdk synth` puis exécutez-la `sam build` avant d'exécuter des `sam local` commandes. Lorsque vous l'exécutez`sam build`, AWS SAM ne crée pas de fonctions ou de couches Lambda qui utilisent des structures spécifiques à l'exécution, par exemple,. ` [NodejsFunction](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_nodejs.NodejsFunction.html) ` `sam build`ne prend pas en charge les [actifs groupés](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.BundlingOptions.html).

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

L'exécution de la commande suivante à partir du répertoire racine du projet AWS CDK permet de créer l'application.

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