Choosing Tests for Infrastructure
An excerpt from Infrastructure as Code, Patterns and Practices by Rosemary Wang
This article discusses testing strategies for infrastructure.
Read it if you’re a sysadmin or software engineer familiar with Python, the basics of provisioning tools like Terraform, and public cloud providers such as Google Cloud Platform that wants to learn more about how to test infrastructure.
Do you need to write most common tests in infrastructure, from unit tests to end-to-end tests? Where should you spend your time and effort in writing them? Your infrastructure testing strategy will evolve depending on the complexity and growth of your system. As a result, you’ll constantly assess which tests will help you catch configuration issues before production.
The test pyramid in figure 1 provides a framework for different types of tests, their scope, and frequency. The widest part of the pyramid indicates that you should have more of this type of test, and the narrowest part indicates that you should have fewer. At the top of the pyramid are end-to-end tests, which may cost more time and money because they require active infrastructure systems. At the bottom of the pyramid are unit tests, which run in seconds and don’t require entire infrastructure systems. I use the test pyramid as a guideline for thinking about infrastructure testing strategy.
In reality, your test pyramid may be shaped more like a rectangular or pear, sometimes with missing levels. You won’t and shouldn’t write every type of test for every infrastructure configuration. At some point, the tests become redundant and impractical to maintain. Depending on the system you want to test, it may not be practical to adhere to the test pyramid in its ideal.
I follow the guidelines in figure 2 to write tests for configurations and modules. In general, I write:
- Static analysis (unit and contract tests) and integration tests for modules using the factory, builder, and prototype pattern
- Unit tests and dynamic analysis (integration and end-to-end) for configurations using a general composite or singleton pattern applied to environments
When running tests against factory, builder, or prototype modules, focus on unit or contract testing to enforce proper configuration, correct module logic, and specific inputs and outputs. Depending on the cost of your development environment, you can write a few integration tests to run against temporary infrastructure resources, which you delete at the end of the test. Optionally, you can write end-to-end tests for modules if your module alone addresses some end-user functionality. By investing some time and effort into writing tests for modules with many inputs and outputs, you ensure that changes don’t affect upstream configuration and that the module can run successfully on its own.
Unlike modules, composite or singleton infrastructure configurations applied to environments don’t involve contract tests. Instead, integration tests can usually determine whether you’ve used a factory, builder, or prototype module correctly. Infrastructure configuration testing strategies require end-to-end testing to determine whether the end user can use the infrastructure system. You’ll usually run integration and end-to-end tests against a long-lived development environment before you roll changes to production.
That’s all for this excerpt.
If you want to learn more about the book, you can check it out on Manning’s liveBook platform here.