繁体   English   中英

如何从_lookup pytest python AWS CDK VPC

[英]How to pytest python AWS CDK VPC from_lookup

当使用使用from_lookup方法获取 VPC 的堆栈时,除非您设置凭证,否则运行单元测试将失败,这是不可取且不实用的

如何编写 pytest 来解决这个问题?

示例堆栈模块ec2_stack.py

# Deps
from aws_cdk import (
    Stack,
    aws_ec2 as _ec2,
)
from constructs import Construct


class Ec2Test(Stack):
    """
    An EC2 test
    """

    def __init__(
        self,
        scope: Construct,
        construct_id: str,
        **kwargs,
    ) -> None:
        super().__init__(scope, construct_id, **kwargs)
        self.vpc_id = self.node.try_get_context("vpc_id")
        self.inst_type = self.node.try_get_context("inst_type")
        self.base_ami_id = self.node.try_get_context("base_ami_id")

        self._vpc = _ec2.Vpc.from_lookup(
            scope=self,
            id="my-vpc",
            vpc_id=self.vpc_id,
        )
        self._machine_image = _ec2.MachineImage.generic_linux(
            {"ap-southeast-2": self.base_ami_id}
        )
        self.__create_instance()

    def __create_instance(self):
        """
        Create EC2 instance resource
        """
        _ec2.Instance(
            self,
            "ec2",
            instance_type=_ec2.InstanceType(self.inst_type),
            vpc=self._vpc,
            machine_image=self._machine_image,
        )

一种解决方案是使用夹具并添加可选参数来传递 IVpc 对象,直到为 CDK 编写模拟库( moto存在模拟 boto3,但找不到 CDK 等效项)

堆栈构造函数更新

    def __init__(
        self,
        scope: Construct,
        construct_id: str,
        vpc: _ec2.IVpc = None,  # New parameter
        **kwargs,
    ) -> None:
        super().__init__(scope, construct_id, **kwargs)
        self.vpc_id = self.node.try_get_context("vpc_id")
        self.inst_type = self.node.try_get_context("inst_type")
        self.base_ami_id = self.node.try_get_context("base_ami_id")
        if vpc is not None:
            # Now VPC can be provided optionally
            self._vpc = vpc
        else:
            self._vpc = _ec2.Vpc.from_lookup(
                scope=self,
                id="my-vpc",
                vpc_id=self.vpc_id,
            )
        self._machine_image = _ec2.MachineImage.generic_linux(
            {"ap-southeast-2": self.base_ami_id}
        )
        self.__create_instance()

示例 pytest 代码: test_ec2_stack_vpc.py

# deps
import aws_cdk as _cdk
from aws_cdk import (
    assertions as assertions,
    aws_ec2 as _ec2,
)
from constructs import Construct
import pytest

from ec2_stack import Ec2Test

EXPECTED_VPC = "vpc-123"
EXPECTED_INST_TYPE = "t3.micro"
EXPECTED_AMI_ID = "ami-123"

TEST_CONTEXT_EC2 = {
      "inst_type": EXPECTED_INST_TYPE,
      "vpc_id": EXPECTED_VPC,
      "base_ami_id": EXPECTED_AMI_ID,
}


@pytest.fixture
def make_vpc():
    def _make_vpc(scope, id):
        return _ec2.Vpc.from_vpc_attributes(
            scope,
            id,
            availability_zones=["ap-southeast-2"],
            vpc_id=EXPECTED_VPC,
            private_subnet_ids=["subnet-9876"],
            private_subnet_names=["priv-8"],
        )

    return _make_vpc


class EmptyStack(_cdk.Stack):
    """
    Stack only to provide context
    """

    def __init__(
        self, scope: Construct, construct_id: str, vpc: _ec2.IVpc = None, **kwargs
    ) -> None:
        super().__init__(scope, construct_id, **kwargs)


def test_ec2_created(make_vpc):
    app = _cdk.App(context=TEST_CONTEXT_EC2)
    e_stack = EmptyStack(app, "empty-stack")
    test_vpc = make_vpc(e_stack, "test-vpc")
    stack = Ec2Test(app, "ec2-stack", vpc=test_vpc)
    template = assertions.Template.from_stack(stack)

    template.has_resource_properties(
        "AWS::EC2::Instance", {"InstanceType": EXPECTED_INST_TYPE}
    )

我认为您可能是从错误的角度考虑这一点:

from方法假定资源在合成期间存在,并生成一个令牌,一旦 CloudFormation 收到合成模板并解析导入from方法中导入的各种资源所需的所有内容,该令牌将与正确的值相对应。

此外,当您对 CDK 进行单元测试时,您实际上所做的只是验证模板是否包含您希望它包含的资源,并具有某些配置。 导入诸如 VPC 之类的资源将具有由任何进程生成它时所具有的任何值(另一个堆栈,组织级别设置功能,等等)。 因此,模拟它并测试它以使其在导入它的堆栈中具有特定值是愚蠢的 - 这可能随时更改,并且您的测试会报告它仍然通过,因为即使您的模拟值不会改变实际资源做到了。

所以,你应该:

  1. 测试需要 VPC 访问的资源是否设置了 VPC 属性。 它们可能会解析为令牌,或者它们可能不是 100% 清楚,但是您可以相信from方法通常会按照描述的方式工作,并且会在部署时添加正确的值 - 您不必测试它确实如此,因为 CDK团队已经这样做了。 - 您不是在此处测试,而只是在资源上存在给定的属性并且它们不是无/空/空。

  2. 然后,根据您的 VPC 创建方式的性质:

    • 如果您在另一个堆栈中控制 VPC,则您可以在那里对其特定值进行单元测试。 只要您和您的团队了解一旦建立更改测试是不好的(并且如果您发现自己经常这样做,那么您的代码需要更改为更可单元测试,而不是您的测试),那么您就可以合理相信一切都会按预期进行

    • 如果您根本不控制 vpc(例如使用默认值或您的组织在其每个子帐户中创建了 vpc),那么您将需要比单元测试更高级别的测试 - 集成/合同测试和健康检查测试(即-测试可以在哪里获得凭据来检查事物)。

当使用 cdk deploy 或从 CodeDeploy 初始化 CloudFormation 部署时,From 方法“基本上”(泛化传入)仅使用现有的 SDK 方法(即:如 boto3)在部署时获取此信息。 无论如何,SDK 只是构建在aws cli sdk 之上,这几乎是每个内部资源在运行时从其他资源获取所需信息的方式。

因为这些方法是从 CDK 团队(和 SDK 团队)内置的,所以您不必测试它们是否按预期从当前测试范围之外的事物导入(在此测试范围内未创建 vpc,因此它超出了其范围),因为您可以相信 AWS 将尽其所能确保其继续按预期运行。 (错误显然会发生,但通常是的) - 毕竟 - 你不会去测试每个导入是否有效,对吧? 或者您安装的每个库,其记录的功能都按预期独立工作(而不是您行为的一部分),对吗? from方法是一回事。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM