Metadata-Version: 2.1
Name: cdktest
Version: 0.0.1
Summary: Simple python test helper for AWS CDK
Author-email: leunguu <liangy3928@gmail.com>
License: Apache-2.0
Project-URL: homepage, https://github.com/LEUNGUU/cdk-python-testing-helper
Project-URL: repository, https://github.com/LEUNGUU/cdk-python-testing-helper
Keywords: CDK,AWS,Python,Test,Helper
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE

<h1 align="center">Python Test Helper for AWS CDK</h1>

<p align="center">
<img alt="Python Version" src="https://img.shields.io/badge/python-3.10%20|%203.11-blue">
<img alt="GitHub Workflow Status (with branch)" src="https://img.shields.io/github/actions/workflow/status/leunguu/cdk-python-testing-helper/tests.yml?branch=main">
<img alt="GitHub" src="https://img.shields.io/github/license/leunguu/cdk-python-testing-helper">
<img alt="PyPI" src="https://img.shields.io/pypi/v/cdk-python-testing-helper">
<img alt="PRs Welcome" src=https://img.shields.io/badge/PRs-welcome-brightgreen.svg>
</p>

This simple helper facilitates testing CDK constructs from Python unit tests, by wrapping the CDK executable and exposing
convenience methods to set up fixtures, execute CDK commands, and parse their output.

It allows for different types of tests: lightweight tests that only use CDK `synthesize` to ensure code is syntactically
correct and the right number and type of resources should be created, or full-fledged tests that run the full `deploy` cycle,
and can then be used to test the actual created resources.

This tool is heavily inspired by this project: [terraform-python-testing-helper](https://github.com/GoogleCloudPlatform/terraform-python-testing-helper).

## Example Usage

The [`tests`](https://github.com/LEUNGUU/cdk-python-testing-helper/tree/main/tests) folder contains simple examples on how to
write tests for both `synth` and `deploy`.

This is a test that uses synth output on an actual module:

```python
import pytest
import cdktest
import json


@pytest.fixture
def output(fixtures_dir):
    cdk = cdktest.CDKTest("custom", fixtures_dir, binary="npx cdk")
    return cdk.synthesize()


def test_vpc_count(output):
    assert len(output.resources["AWS::EC2::VPC"]) == 1

def test_subnet_type(output):
    subnet_output = output.resources["AWS::EC2::Subnet"]
    tag_list = map(lambda x: x["Tags"], subnet_output)
    type_count = Counter(
        [
            item["Value"]
            for sublist in tag_list
            for item in sublist
            if item["Key"] == "aws-cdk:subnet-type"
        ]
    )
    assert (
        type_count["Private"] == 2
    ), f'Expected number of Private subnet is 2, got {type_count["Private"]}'
    assert (
        type_count["Public"] == 2
    ), f'Expected number of Public subnet is 2, got {type_count["Public"]}'
```

## Caching

The CDKTest synthesize and deploy methods have the ability to cache its associate output to a local .cdktest-cache directory. This cache directory
will work as a flag. For subsequent calls of the method, the cached folder will be recognized and avoid calling the actual underlying `cdk` command
again and again. Using the cache flag can be significantly faster than running the `cdk` command again especially if the command is time-intensive.

The benefits of the caching feature include:

  - Faster setup time for testing cdk constructs that don't change between testing sessions

Please see the following example for how to use it:
```python
import pytest
import cdktest


@pytest.fixture(scope="session")
def cdk(request, fixtures_dir):
    cdk = cdktest.CDKTest(
        appdir="no_change",
        basedir=fixtures_dir,
        binary="npx cdk",
        enable_cache=request.param,
    )
    yield cdk

    _LOGGER.debug("Removing cache dir")
    try:
        shutil.rmtree(cdk.cache_dir)
    except FileNotFoundError:
        _LOGGER.debug("%s does not exists", cdk.cache_dir)


@pytest.mark.parametrize("cdk", [True], indirect=True)
def test_use_cache(cdk):
    """
    Ensures cache is used and runs the execute_command() for first call of the
    method only
    """
    for method in cache_methods:
        with patch.object(
            cdk, "execute_command", wraps=cdk.execute_command
        ) as mock_execute_command:
            for _ in range(2):
                getattr(cdk, method)(use_cache=True)
            assert mock_execute_command.call_count == 1

```
## Testing

Tests use the `pytest` framework and have no other dependency except on the Python cdk library.
