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/Тестирование/tf-test-mocks

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

Mock-провайдеры: mock_provider, override_resource, override_data

Mock-провайдер заменяет реальный AWS на синтезированные ответы, тест бежит без облака, секунды вместо минут. Объявляется в `*.tftest.hcl` через `mock_provider "aws"`. Точечно подменить отдельный ресурс или data-source, `override_resource` и `override_data`. Без mock'ов любой `command = apply` будет требовать LocalStack.

view as markdownaka: terraform-mock-provider, tftest-mocks, terraform-override

Зачем mock'и

terraform test с command = apply стандартно ходит в провайдера. AWS деньги и латентность, LocalStack, нужно поднять и ждать. Для unit-тестов модуля это перебор: проверить генерацию ARN из имени бакета можно без единого API-вызова.

Mock-провайдер отвечает на вызовы провайдера синтетическими данными. Доступен с Terraform 1.7.

mock_provider целиком

hcl
# tests/unit.tftest.hcl
mock_provider "aws" {}
run "naming" {
  command = apply  # apply ок, mock не пойдёт в облако
  variables {
    name = "test-bucket"
  }
  assert {
    condition     = aws_s3_bucket.this.bucket == "test-bucket"
    error_message = "name not propagated"
  }
}

mock_provider "aws" {} без аргументов, каждый ресурс/data-source AWS получает дефолтные mock-значения. Terraform сам генерирует placeholder'ы: строки, "unknown", числа, 0, bool, false, sets/lists, пустые.

Apply «выполняется», но в облако ничего не идёт.

Default-значения для конкретных типов

Если генерированные дефолты ломают логику (например модуль читает aws_s3_bucket.this.id и из него строит другие имена) задай дефолты:

hcl
mock_provider "aws" {
  mock_resource "aws_s3_bucket" {
    defaults = {
      id  = "mocked-bucket-id"
      arn = "arn:aws:s3:::mocked-bucket"
    }
  }
  mock_data "aws_caller_identity" {
    defaults = {
      account_id = "111111111111"
      arn        = "arn:aws:iam::111111111111:user/test"
      user_id    = "AIDA1234567890"
    }
  }
}

Теперь aws_s3_bucket.this.id стабильно вернёт mocked-bucket-id во всех тестах в этом файле.

Точечный override на один run

Файл-level mock'и одинаковы для всех run. Если в одном сценарии нужно специфичное значение, override_resource/override_data внутри run:

hcl
run "private_bucket_acl" {
  command = apply
  override_resource {
    target = aws_s3_bucket.this
    values = {
      id  = "specific-private-bucket"
      arn = "arn:aws:s3:::specific-private-bucket"
    }
  }
  assert {
    condition     = aws_s3_bucket_acl.this.bucket == "specific-private-bucket"
    error_message = "ACL refers to wrong bucket"
  }
}

target, адрес ресурса в модуле, который тестируешь. Override приоритетнее чем mock_resource ... defaults на уровне файла.

Без mock_provider, только override

Если основная масса тестов реальная (LocalStack), а нужно подменить один data-source чтобы не зависеть от внешнего источника, mock_provider не объявляй, используй только override:

hcl
run "with_fixed_account" {
  command = plan
  override_data {
    target = data.aws_caller_identity.current
    values = {
      account_id = "999999999999"
    }
  }
  assert {
    condition     = local.bucket_name == "logs-999999999999"
    error_message = "account_id not woven into name"
  }
}

Остальные ресурсы пойдут к реальному провайдеру (или LocalStack, куда настроен). Только aws_caller_identity подменён.

Какие тесты, mock, какие, real

ТестируюТип теста
Генерация имени из переменныхmock, облако не нужно
Условную логику (count = var.enabled ? 1 : 0)mock
Передачу значений между ресурсами модуляmock
Что модуль реально создаёт ресурс с правильным configreal (LocalStack или AWS)
Что cross-resource политики (bucket policy) подтягиваютсяreal

Правило: если ассерт можно написать без атрибутов «known after apply» делай mock. Сэкономишь часы CI.

Mock'ам не нужен init -upgrade

terraform init с mock'ом пройдёт быстрее, Terraform не качает реальный провайдер, только schema из официального плагина (для type-checking). В CI экономия минут.

Поведение по умолчанию: что mock возвращает

Если не задал defaults, mock-провайдер придумывает значения по schema атрибута:

Тип атрибутаMock-значение
string"foo"
number0
boolfalse
list/set/mapпустое
objectобъект с дефолтами вложенных полей
Optional + не requirednull

Это значит: атрибуты типа id/arn получат строку "foo". Если две reference'а строятся на разные aws_s3_bucket.X.id, они получат одинаковое "foo". Логика, зависящая от уникальности, сломается. Лекарство, задать defaults для каждого ресурса.

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

  • Mock'и работают только в *.tftest.hcl. В обычном .tf нет блока mock_provider. Нельзя «протестировать через terraform plan руками». Только terraform test.

  • Атрибуты, вычисляемые провайдером сложной логикой, не моделируются. Например aws_iam_policy_document, это data-source, который локально рендерит JSON. Mock вернёт placeholder JSON, а не правильную политику. Для проверки IAM-политик нужен реальный data-source или явный override на каждое поле.

  • Mock-default'ы, не fixture'ы. Они не сохраняют состояние между run'ами. Если первый run меняет aws_s3_bucket.this, второй run получит снова mock-default, а не изменённое значение. Это runner'у нравится, тестировщику, не всегда.

  • override_resource использует module-локальный адрес. Не module.X.aws_s3_bucket.this, а просто aws_s3_bucket.this предполагается, что тест запущен в директории модуля.

  • Provider-level mock не покрывает sources, объявленные через data в одноименных провайдерах разных alias'ов. aws.eu нужен отдельный mock_provider "aws" { alias = "eu" }.

§ команды

bash
terraform test

Стандартный запуск. С mock_provider гоняется быстро.

bash
terraform test -verbose

Видишь какие override применились на каждом run.

bash
terraform plan -input=false

Mock-блоки игнорируются вне тестов. Этот plan пойдёт в реальный provider.

§ см. также

  • terratest-basicsTerratest: интеграционные тесты Terraform на GoTerratest, Go-библиотека от Gruntwork. Поднимает Terraform, ходит по AWS-API проверять что ресурсы реально созданы такими, как ожидаем, затем сносит. Тяжелее нативного `.tftest.hcl`, но даёт то, чего тот не даст: проверки облачного состояния, HTTP-запросы к подъятому сервису, table-driven тесты, retry-логика. Тесты на Go в `_test.go` файлах рядом с модулями.
  • iac-testing-theoryЧто тестировать в Terraform, а что: не надоИнфраструктура, не приложение, тест-пирамиду применять буквально не стоит. Тестируй контракты модулей, бизнес-правила, сложные expressions, рефакторинги без destroy. Не тестируй что provider работает, что AWS-API отвечает 200, и тривиальный `name = var.name`. Цель, ловить регрессии, не доказывать корректность.
  • tf-data-sourcedata-блок: читаем то, что уже есть в облакеdata, это блок, который запрашивает существующую инфру и отдаёт её атрибуты в HCL. Terraform ничего не создаёт; он только читает. Используется чтобы привязаться к ресурсам, которые сделаны не Terraform'ом или живут в другом проекте.
  • localstack-providerLocalStack: учебный AWS, который живёт в DockerLocalStack эмулирует AWS API локально, в Docker-контейнере. Terraform думает что работает с настоящим AWS, но никаких реальных ресурсов не создаётся и денег не тратится. Идеально для учёбы и тестов.
Footer
linuxlab-УчебникиЦеныО платформеКонфиденциальность и куки
Copyright © 2026 LinuxLab. Все права защищены.