linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
Intro
Lessons
Footer
linuxlab-УчебникиЦеныО платформеКонфиденциальность и куки
Copyright © 2026 LinuxLab. Все права защищены.
linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
  • Введение
  • Уроки
  • How it works
  • База знаний
  • Шпаргалка
  • Capstone
  • Собеседование
home/terraform/kb/Тестирование/iac-testing-theory

kb/testing ── Тестирование ── intermediate

Что тестировать в Terraform, а что: не надо

Инфраструктура, не приложение, тест-пирамиду применять буквально не стоит. Тестируй контракты модулей, бизнес-правила, сложные expressions, рефакторинги без destroy. Не тестируй что provider работает, что AWS-API отвечает 200, и тривиальный `name = var.name`. Цель, ловить регрессии, не доказывать корректность.

view as markdownaka: iac-testing, terraform-testing-strategy, testing-pyramid-terraform

Тест-пирамида для инфры не работает

Классическая пирамида: 70% unit, 20% integration, 10% e2e. Для приложения ок. Для Terraform, проблематично.

  • Unit-тест Terraform-модуля стоит дёшево (.tftest.hcl + mock_provider), но проверяет узкое: «модуль выкатил то, что HCL сказал выкатить». От бага в провайдере или AWS-API он не защитит.
  • Integration дороже на порядок (поднять LocalStack/aws, минуты), но реально проверяет, что результат, рабочая инфра.
  • E2E, собственно production-deploy. Само развёртывание уже есть в pipeline; «отдельный e2e», обычно дублирование.

Реалистичный профиль для Terraform-репо: 40% unit, 40% integration на LocalStack, 20% policy/compliance, e2e, production-pipeline.

Что тестировать

1. Контракт модуля

Модуль принимает var.name и выкатывает aws_s3_bucket.this. Тест: передал «foo» → в plan aws_s3_bucket.this.bucket == "foo". Это страховка от случайного переименования переменной.

hcl
# tests/contract.tftest.hcl
run "var_name_propagates" {
  command = plan
  variables { name = "foo" }
  assert {
    condition     = aws_s3_bucket.this.bucket == "foo"
    error_message = "var.name does not reach bucket"
  }
}

2. Бизнес-правила (политика)

Encryption обязателен. Tag CostCenter обязателен. Не публичный по умолчанию. Это уровень компании, не модуля. Лучше, policy-as-code (tf-policy-as-code / terraform-compliance) на plan-файл в CI.

3. Сложные expressions

Простой name = var.name тестировать незачем. А вот:

hcl
locals {
  bucket_name = "${var.team}-${var.purpose}-${random_id.suffix.hex}"
  tags = merge(
    var.default_tags,
    { Team = var.team, ManagedBy = "terraform" },
  )
}

Здесь логика. Тест: «при team=ai и purpose=logs имя начинается с ai-logs-».

4. Рефакторинги (moved-блоки)

Перенесли aws_s3_bucket.logs в модуль. Тест на чистый plan:

hcl
run "no_diff_after_refactor" {
  command = plan
  # ассерт что plan ничего не делает
}

Сам Terraform pluralized сказал «no changes», но без assert в тесте этот факт нигде не зафиксирован.

5. Преконды/посткондишены

hcl
variable "env" {
  type = string
  validation {
    condition     = contains(["dev", "stage", "prod"], var.env)
    error_message = "env must be dev/stage/prod"
  }
}

Тест с expect_failures = [var.env] при env = "xyz", гарантирует, что validation сработает. См. tf-test-framework.

Что НЕ тестировать

1. Что HCL правильно описывает AWS API

hcl
resource "aws_s3_bucket" "this" {
  bucket = "foo"
}

Тестировать «когда apply, в AWS появится бакет foo», бесполезно. Это работа HashiCorp + AWS SDK. Ты не тестируешь компилятор, ты тестируешь свой код.

2. Тривиальный pass-through

hcl
output "arn" {
  value = aws_s3_bucket.this.arn
}

Тест «output arn равен ARN», бессмысленный. Нечего ломаться.

3. Что облако ведёт себя как облако

«После apply бакет действительно отвечает 200 на HEAD», это smoke-test уровня операций, а не теста модуля. Делается в production через мониторинг, а не в test suite.

4. Performance

Тестировать «apply 100 ресурсов за < 60 секунд», flaky всегда. Performance Terraform зависит от latency provider'а и сети. Если хочется, отдельный бенч раз в неделю, не в каждом PR.

Уровни и инструменты

УровеньЧтоЧем
Static analysisСинтаксис, форматирование, типичные ошибкиterraform fmt -check, terraform validate, tf-checkov
LintСтиль, depracated args, провайдерские best-practicestflint с rule-set'ом
Unit (модуль в изоляции)Контракт модуля, наименования, бизнес-правила.tftest.hcl + mock_provider
IntegrationРеально создаются ресурсы, cross-resource взаимодействия.tftest.hcl с command = apply на LocalStack, либо Terratest
PolicyКорпоративные правила (тэги, security)OPA+Rego, terraform-compliance, Checkov
E2EРазвёртывание prod-окруженияСам production-pipeline

Golden plan

Один лёгкий, но мощный тест: «текущий код даёт plan, побитово совпадающий с сохранённой эталонной строкой». При любом изменении (HCL, провайдер, модуль) diff. Ревьюер видит точно что изменилось.

Реализация:

bash
terraform plan -out=plan.tfplan
terraform show -no-color plan.tfplan > plan.golden

Закоммитили plan.golden. В CI:

bash
terraform plan -out=plan.tfplan
terraform show -no-color plan.tfplan > plan.current
diff plan.golden plan.current || exit 1

Когда меняешь HCL, обновляешь golden. PR показывает diff в HCL и diff в golden, обе стороны видны. Полезно на root-модулях с zero-diff-ожиданием.

Сколько тестов

Не больше, чем оправдано. Признаки переборщил:

  • Тесты дольше, чем сам apply.
  • Чаще ломаются от обновления провайдера, чем от твоего кода.
  • В тестах больше copy-paste, чем в production-коде.
  • Никто не может объяснить, что именно этот тест ловит.

Признаки недотестировал:

  • Boilerplate-ошибки доходят до prod.
  • Рефакторинги ломают что-то, что не было заметно в plan.
  • Бизнес-правила нарушаются (tag забыли, encryption выключили).

Балансируй между.

Подводные камни

  • Тесты, обязательство, не актив. Каждый тест надо поддерживать. Старый тест, который никто не понимает, но боится удалить, токсичный долг.

  • Mock'и не ловят интеграционные баги. Юнит-тест с mock_provider может pass'нуться, а реальный apply упадёт, например, потому что AWS API требует определённый порядок аргументов или формат имени.

  • Дешёвый тест дорог в обслуживании. Сценарий «при var.foo=true, plan показывает 5 ресурсов», простой, но при добавлении 6-го ломается. Лучше тестировать инварианты («каждый аккаунт имеет KMS-key»), чем точные числа.

  • Тесты не заменяют код-ревью. Хорошо написанный HCL ревьюится быстрее, чем плохой код с 100% test coverage. Тесты, в дополнение.

  • Production-debug пишется тестами. Каждый раз когда что-то сломалось в production, добавляй тест, который бы это поймал. Это единственный надёжный способ копить test suite, который реально ловит реальные баги.

§ см. также

  • tf-test-mocksMock-провайдеры: mock_provider, override_resource, override_dataMock-провайдер заменяет реальный AWS на синтезированные ответы, тест бежит без облака, секунды вместо минут. Объявляется в `*.tftest.hcl` через `mock_provider "aws"`. Точечно подменить отдельный ресурс или data-source, `override_resource` и `override_data`. Без mock'ов любой `command = apply` будет требовать LocalStack.
  • terratest-basicsTerratest: интеграционные тесты Terraform на GoTerratest, Go-библиотека от Gruntwork. Поднимает Terraform, ходит по AWS-API проверять что ресурсы реально созданы такими, как ожидаем, затем сносит. Тяжелее нативного `.tftest.hcl`, но даёт то, чего тот не даст: проверки облачного состояния, HTTP-запросы к подъятому сервису, table-driven тесты, retry-логика. Тесты на Go в `_test.go` файлах рядом с модулями.
  • terraform-complianceterraform-compliance: BDD-проверки на plan-файлУтилита terraform-compliance читает plan-файл (`plan.json`) и применяет к нему BDD-правила в Gherkin. «Given a resource of type X, it must contain a property Y», читаемо для не-инженеров, гарантирует политику до apply. Альтернатива OPA/Rego для команд, которые предпочитают естественный язык, но менее мощная, нельзя писать сложные cross-resource проверки.
  • tf-policy-as-codeOPA + Rego, policy as code для Terraform planPolicy-as-code = правила («все S3 шифрованы», «никаких IAM с *») написаны кодом, гонятся в CI, fail'ят PR. OPA, стандарт, Rego, язык. conftest, обёртка с CLI-friendly выводом; читает plan.json, прогоняет правила, exit 0/1. Зрелее и дороже на старте, чем Checkov, но позволяет cross-resource правила любой сложности.
Footer
linuxlab-
Copyright © 2026 LinuxLab. Все права защищены.
Учебники
Цены
О платформе
Конфиденциальность и куки