Testing Patterns
Simfra is well-suited for testing Terraform modules. Write your module normally, point it at Simfra, and verify that it produces the expected resources and outputs.
Prerequisites
- Simfra running on
localhost:4599(see Installation) - Environment variables set (see Provider Configuration)
- Terraform 1.6+
Plan / Apply / Verify / Destroy
The basic testing cycle:
# 1. Plan - verify no errors, check resource count
terraform plan -out=tfplan
# Inspect the plan output for expected resources
# 2. Apply
terraform apply tfplan
# 3. Verify outputs
terraform output -json | jq .
# 4. Verify resources exist via AWS CLI
aws ec2 describe-vpcs --filters Name=tag:Name,Values=my-vpc
# 5. Destroy
terraform destroy -auto-approve
Simfra is in-memory by default, so this cycle runs in seconds. There are no API rate limits and no eventual consistency delays.
Verifying State with Data Sources
Use Terraform data sources to verify that resources were created correctly:
module "network" {
source = "./modules/network"
}
# Verify the VPC exists and has the expected CIDR
data "aws_vpc" "check" {
id = module.network.vpc_id
}
output "verified_cidr" {
value = data.aws_vpc.check.cidr_block
}
# Verify subnets were created in the right AZs
data "aws_subnets" "check" {
filter {
name = "vpc-id"
values = [module.network.vpc_id]
}
}
output "subnet_count" {
value = length(data.aws_subnets.check.ids)
}
Data sources read from Simfra the same way they read from AWS, so any validation logic in your Terraform code works without modification.
Using terraform test
Terraform 1.6+ supports native test files (.tftest.hcl). These work with Simfra out of the box.
Module Under Test
# modules/network/main.tf
variable "vpc_cidr" {
type = string
default = "10.0.0.0/16"
}
variable "subnet_count" {
type = number
default = 2
}
resource "aws_vpc" "this" {
cidr_block = var.vpc_cidr
tags = {
Name = "test-vpc"
}
}
resource "aws_subnet" "this" {
count = var.subnet_count
vpc_id = aws_vpc.this.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index)
}
output "vpc_id" {
value = aws_vpc.this.id
}
output "subnet_ids" {
value = aws_subnet.this[*].id
}
Test File
# tests/network.tftest.hcl
run "creates_vpc_and_subnets" {
command = apply
assert {
condition = output.vpc_id != ""
error_message = "VPC ID should not be empty"
}
assert {
condition = length(output.subnet_ids) == 2
error_message = "Expected 2 subnets"
}
}
run "custom_cidr" {
command = apply
variables {
vpc_cidr = "172.16.0.0/16"
subnet_count = 3
}
assert {
condition = length(output.subnet_ids) == 3
error_message = "Expected 3 subnets with custom count"
}
}
Running Tests
terraform test
Each run block creates a fresh apply/destroy cycle. Against Simfra, the entire test suite runs in seconds.
Testing Modules in Isolation
Test individual modules without a full root configuration:
project/
modules/
network/
main.tf
outputs.tf
compute/
main.tf
variables.tf
tests/
network.tftest.hcl
compute.tftest.hcl
Each test file can target a specific module and assert on its outputs independently. Since Simfra has no costs, you can run terraform test on every commit.
Asserting on Resource Attributes
Use data sources inside test runs to inspect resources beyond what outputs expose:
run "vpc_has_dns_enabled" {
command = apply
assert {
condition = output.vpc_id != ""
error_message = "VPC should be created"
}
}
run "verify_vpc_dns" {
command = plan
module {
source = "./tests/helpers/check-vpc"
}
variables {
vpc_id = run.vpc_has_dns_enabled.vpc_id
}
assert {
condition = data.aws_vpc.this.enable_dns_support
error_message = "VPC should have DNS support enabled"
}
}
Fast Iteration Tips
- No
SIMFRA_DATA_DIR- leave persistence off for testing. State resets on restart, giving you a clean slate. SIMFRA_BOOTSTRAP=standard- pre-creates default VPCs and KMS keys so modules that depend on default resources work immediately.- Parallel applies - Simfra handles concurrent requests. Run multiple test suites in parallel.
-parallelism=30- Terraform defaults to 10 concurrent operations. Simfra can handle more.- No state locking needed - with a local backend and ephemeral Simfra, there is no contention.
CI Integration
Simfra runs as a single binary or Docker container, making it straightforward to add to CI pipelines:
# GitHub Actions example
- name: Start Simfra
run: |
docker run -d --name simfra -p 4599:4599 \
-e SIMFRA_BOOTSTRAP=standard \
ghcr.io/simfra-dev/simfra:latest
- name: Wait for healthy
run: |
for i in $(seq 1 30); do
curl -sf http://localhost:4599/_simfra/health && break
sleep 1
done
- name: Terraform test
env:
AWS_ENDPOINT_URL: http://localhost:4599
AWS_ACCESS_KEY_ID: AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
AWS_DEFAULT_REGION: us-east-1
run: terraform test
Next Steps
- Provider Configuration - the canonical Terraform provider setup for Simfra
- Bootstrapping Your Account - pre-create default resources that modules depend on
- Resource ID Overrides - pin resources to specific IDs for deterministic tests