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/lessons/tf-production-04-mock-providers

lesson ── terraform-production ── ~14 мин ── 5 шагов

Mock-провайдеры, тесты без облака

Apply-тесты дорогие, даже LocalStack секунды на каждый запуск. Mock-провайдеры заменяют реальный AWS на синтезированные ответы; command = apply становится быстрым и offline. mock_provider, override_resource, override_data, три инструмента. С Terraform 1.7+.

▶ интерактивный sandbox

Поднимется пара контейнеров: terraform 1.9 и localstack 3.8 в одной сети. В браузере откроется терминал, можно сразу terraform init. Каждый шаг проверяется автоматически. TTL 45 минут, без регистрации.

запустить sandbox →

stack ── terraform · localstack · 1 GB RAM · самоуничтожается через 45 мин простоя

Шаги

  1. 01

    Модуль с двумя cross-referencing ресурсами

    Для иллюстрации mock'а с defaults нужен модуль, где один ресурс ссылается на другой через id.

    bash
    cd /home/student/tf-mocks/modules/audited-bucket
    cat > main.tf <<'EOF'
    resource "aws_s3_bucket" "this" {
      bucket = var.name
    }
    resource "aws_s3_bucket_versioning" "this" {
      bucket = aws_s3_bucket.this.id
      versioning_configuration {
        status = "Enabled"
      }
    }
    resource "aws_s3_bucket_public_access_block" "this" {
      bucket = aws_s3_bucket.this.id
      block_public_acls       = true
      block_public_policy     = true
      ignore_public_acls      = true
      restrict_public_buckets = true
    }
    EOF
    cat > variables.tf <<'EOF'
    variable "name" {
      type = string
    }
    EOF
    cat > outputs.tf <<'EOF'
    output "id" {
      value = aws_s3_bucket.this.id
    }
    EOF

    Три ресурса: бакет, versioning, public-access-block. Versioning и ACL ссылаются на aws_s3_bucket.this.id.

    ✓ Модуль с cross-references готов.

  2. 02

    Bare mock_provider, что получится

    bash
    cat > /home/student/tf-mocks/modules/audited-bucket/tests/mock_bare.tftest.hcl <<'EOF'
    mock_provider "aws" {}
    run "with_bare_mock" {
      command = apply
      variables {
        name = "test-mocked"
      }
      assert {
        condition     = aws_s3_bucket.this.bucket == "test-mocked"
        error_message = "bucket name not propagated"
      }
    }
    EOF
    cd /home/student/tf-mocks/modules/audited-bucket
    terraform init -backend=false
    terraform test -filter=tests/mock_bare.tftest.hcl

    Должно показать pass. mock_provider "aws" {}, генерит дефолты по schema, никакого облака. Apply, мгновенный.

    ✓ Bare mock работает. Один тест без LocalStack.

  3. 03

    mock_resource с defaults, стабильные id

    Голый mock возвращает "foo" для всех string-атрибутов. Если два ресурса ссылаются на aws_s3_bucket.this.id, оба получают "foo" это окей, но непрозрачно. Зафиксируем явный id:

    bash
    cat > /home/student/tf-mocks/modules/audited-bucket/tests/mock_with_defaults.tftest.hcl <<'EOF'
    mock_provider "aws" {
      mock_resource "aws_s3_bucket" {
        defaults = {
          id  = "mocked-id-001"
          arn = "arn:aws:s3:::mocked-id-001"
        }
      }
    }
    run "versioning_references_correct_bucket" {
      command = apply
      variables {
        name = "test-with-defaults"
      }
      assert {
        condition     = aws_s3_bucket_versioning.this.bucket == "mocked-id-001"
        error_message = "versioning should reference bucket id mocked-id-001"
      }
      assert {
        condition     = aws_s3_bucket_public_access_block.this.bucket == "mocked-id-001"
        error_message = "PAB should reference bucket id mocked-id-001"
      }
    }
    EOF
    terraform test -filter=tests/mock_with_defaults.tftest.hcl

    Должно показать pass. Versioning и PAB корректно ссылаются на mocked-id-001, потому что mock зафиксировал это для bucket'а.

    ✓ Cross-resource references проверены без облака.

  4. 04

    override_resource, точечная подмена

    Иногда базовые mock-defaults подходят для большинства run'ов, но в одном, другое значение. override_resource внутри run'а приоритетнее, чем file-level mock.

    bash
    cat > /home/student/tf-mocks/modules/audited-bucket/tests/override.tftest.hcl <<'EOF'
    mock_provider "aws" {
      mock_resource "aws_s3_bucket" {
        defaults = {
          id = "default-id"
        }
      }
    }
    run "default_mock_used" {
      command = apply
      variables { name = "x" }
      assert {
        condition     = aws_s3_bucket_versioning.this.bucket == "default-id"
        error_message = "expected default-id"
      }
    }
    run "override_for_this_run" {
      command = apply
      variables { name = "y" }
      override_resource {
        target = aws_s3_bucket.this
        values = {
          id = "specific-override-id"
        }
      }
      assert {
        condition     = aws_s3_bucket_versioning.this.bucket == "specific-override-id"
        error_message = "expected override id"
      }
    }
    EOF
    terraform test -filter=tests/override.tftest.hcl

    Должно показать 2 passed. Первый run использует file-level default, второй, свой override. Это полезно для «общий тест + специальные кейсы», без дублирования mock-конфига.

    ✓ Mock и override работают в связке.

    То же самое на OpenTofu

    OpenTofu держит CLI и state совместимыми с Terraform по командам этого шага: миграция обычно проходит через mv .terraform .terraform.bak; tofu init -upgrade. Но при первом переходе сделай backup state и прогон на feature-branch - расхождения концентрируются в новых фичах (variables в backend, state-encryption, OCI registry-backed модули). См. tf-opentofu-parity для полной матрицы.

    • → OpenTofu parity
  5. 05

    Сравни скорость mock vs LocalStack-apply

    Кратко покажем разницу. Запусти все mock-тесты с time:

    bash
    time terraform test \
      -filter=tests/mock_bare.tftest.hcl \
      -filter=tests/mock_with_defaults.tftest.hcl \
      -filter=tests/override.tftest.hcl

    Записывай time real (например 1.2s).

    Создай эквивалентный non-mock тест:

    bash
    cat > tests/realstack.tftest.hcl <<'EOF'
    provider "aws" {
      region                      = "us-east-1"
      access_key                  = "test"
      secret_key                  = "test"
      s3_use_path_style           = true
      skip_credentials_validation = true
      skip_metadata_api_check     = true
      skip_requesting_account_id  = true
      endpoints {
        s3  = "http://localstack:4566"
        iam = "http://localstack:4566"
        sts = "http://localstack:4566"
      }
    }
    run "real_apply" {
      command = apply
      variables { name = "real-test-bucket" }
      assert {
        condition     = aws_s3_bucket.this.id == "real-test-bucket"
        error_message = "id mismatch"
      }
    }
    EOF
    time terraform test -filter=tests/realstack.tftest.hcl

    Сравни, LocalStack дольше из-за реального provider'а и HTTP-вызовов. Mock в 5-20 раз быстрее. На большом test-suite разница, минуты.

    Это то, ради чего mock'и существуют. В CI: основная масса unit-тестов на mock'ах; пара integration-тестов на LocalStack или AWS.

    ✓ Mock vs real: разница ощутима. Mock, основная масса CI, LocalStack, выборочно.

    Когда mock, плохой выбор

    Mock vs real, не догма. Случаи когда mock проигрывает:

    1. Тест на корректность HCL → реальный API. Например, aws_iam_policy_document, это data-source, локально рендерит JSON. Mock вернёт placeholder, реальный data-source, настоящую политику. Если ассерт length(jsondecode(...)) == 5, нужен реальный.

    2. Cross-resource через computed-атрибут. Если ресурс A возвращает computed arn нестандартной формы, и B парсит её mock возвращает "foo", B не парсится, тест ложно валится. Override спасает, но это бойлерплейт.

    3. Тестируешь сам provider. Mock проверяет «HCL правильно описывает то, что хочешь». Если хочешь убедиться, что AWS принимает твой config, нужен реальный.

    Правило: mock для «тест на свой код», real для «тест на интеграцию с облаком».

    • → Mock-провайдеры целиком
    • → Что тестировать

Что ты узнал

mock_provider "aws" {} в *.tftest.hcl подменяет провайдера на fake. mock_resource "X" { defaults = {...} }, задаёт значения для конкретного типа. override_resource / override_data, точечная подмена в одном run-блоке.

команды

  • terraform test -filter=tests/mocked.tftest.hclmock-тесты быстрее, все apply'ы offline.
  • terraform test -verboseвидишь какие override применились.

концепции

  • · mock_provider раскрывает атрибуты в дефолты по schema
  • · defaults фиксируют id/arn чтобы cross-resource references работали
  • · override_resource внутри run-блока, приоритет над mock_resource на уровне файла

← предыдущий

dynamic блоки: повторяющиеся подблоки

следующий →

Blue-green миграция legacy в Terraform

Footer
linuxlab-
Copyright © 2026 LinuxLab. Все права защищены.
Учебники
Цены
О платформе
Конфиденциальность и куки