Terraform Test - how to reference mock objects correct

Hello community,

I need some help to understand Terraform Test Mocks.

Use case:
I want to write a test for my uptime check in Google-Cloud-Platform (GCP). This resource require a compute instance (virtual machines in GCP), so it can checks the uptime of this compute instance. I don’t want to create a compute instance for this test, I only want to create a “uptime check”, a “alert”, and some other related resources in my Terraform module.
So the idea is to mock this compute instance, instead of creating a separate instance for testing.

My problem:
At one point in my test I want to tell my “uptime check” use the mock_compute_instance and don’t try to find a real instance in the infrastructure. In my Terraform code I have two Parameter instance_id and instance_name which I normally use to connect my “uptime check” to a real “compute instance”. I guess I can reference here the mock object. I am right? But if I execute Terrafrom test it returns:

tests/uptime_check_mock.tftest.hcl... in progress
  run "deployment_test"... fail
╷
│ Error: Invalid reference
│ 
│   on tests/uptime_check_mock.tftest.hcl line 38, in run "deployment_test":
│   38:     instance_id   = data.google.google_mock.google_compute_instance
│ 
│ You can only reference earlier run blocks, file level, and global variables while defining variables from inside a run block.

The code:

mock_provider "google" {
  alias = "google_mock"

  mock_data "google_compute_instance" {
    defaults = {
      name = "tf-test-mock-vm"
      instance_id   = "654321"
      instance_name = "HuggaBugga"
    }
  }
}

variables {
  project_id = "test-project"
  region  = "europe-west3"

  # HERE I WANT TO REFERENCE THE MOCKED COMPUTE INSTANCE which is not working

  #instance_id   = google.google_mock.mock_data.google_compute_instance
  #instance_name = data.google_compute_instance
}

run "deployment_test" {
  command = apply
  providers = {
    google = google.google_mock
  }

  variables {
    display_name  = "Terraform-Test uptime check for vm instance"
    tcp_port     = "80"
    period        = "60s" 
  }

  module {
    # Here I create the uptime check which should be tested 
    source = "./"
  }
}

As you can see in my example code above I create a a mock_provider and inside of it I create a mock_data object which I fill with parameters. Now I want to use this data_mock object and let the “uptime check” use it. I not know how to reference to the mocked data or resource object.

I followed mainly this documentation and search in the forum without any clear answer for me.

Can somebody provide my an example?
Thank you in advance.

Do you have a snippet of the terraform code you’re trying to test as well? Just to be clear, you’re trying to test your terraform module’s behavior, not test / assert the behavior of an actual uptime check, right?

I’m also not sure you can output a mocked data resource into a variable - that is, if the data resource is defined in your code, you can mock it; I think mocking the data object in the provider code will only work if there’s a data resource in your test code that the uptime check is referencing… But if it’s just a variable that you’re passing into your module, you don’t need to mock anything in the provider - you can just directly pass the value you want.

So, depending on what you’re trying to do, you may not need to mock anything at all.

If you’re defining the resource in your code, instead of the instance, you probably need to mock the resource instead.

So, without knowing exactly how your module code looks, if you were trying to test that a data resource in the module got the instance by name correctly, you could do something like this:

in test.tf (and variables.tf), or whatever you want to name it

# These would normally be in, say, variables.tf, but including all together for
# convenience / simplicity
variable "display_name" {
  type = string
  default = "Default value"
}

variable "period" {
  type = string
}

variable "project" {
  type    = string
  default = "test-project"
}

variable "tcp_port" {
  type = number
}

variable "zone" {
  type    = string
  default = "europe-west3-a"
}

## Here's your module code
data "google_compute_instance" "foo" {
  project = var.project
  name    = "tf-test-mock-vm"
  zone    = var.zone
}

resource "google_monitoring_uptime_check_config" "http" {
  display_name = var.display_name
  timeout      = "60s"

  http_check {
    path         = "/foo"
    port         = var.tcp_port
  }

  monitored_resource {
    type = "uptime_url"
    labels = {
      project_id = var.project
      host       = data.google_compute_instance.foo.network_interface.0.access_config.0.nat_ip
    }
  }
}

in test.tftest.hcl or tests/test.tftest.hcl:

mock_provider "google" {
  alias = "google_mock"

  mock_data "google_compute_instance" {
    # data.google_compute_instance.foo.network_interface.0.access_config.0.nat_ip
    defaults = {
      name          = "tf-test-mock-vm"
      network_interface = [
        {
          access_config = [
            {
              nat_ip = "4.4.4.4",
            }
          ]
        }
      ]
    }
  }
}

variables {
  project_id = "test-project"
  region     = "europe-west3"

  # HERE I WANT TO REFERENCE THE MOCKED COMPUTE INSTANCE which is not working

  #instance_id   = google.google_mock.mock_data.google_compute_instance
  #instance_name = data.google_compute_instance
}

run "deployment_test" {
  command = apply
  providers = {
    google = google.google_mock
  }

  variables {
    display_name = "Terraform-Test uptime check for vm instance"
    tcp_port     = "80"
    period       = "60s"
  }

  assert {
    condition = google_monitoring_uptime_check_config.http.display_name == "Terraform-Test uptime check for vm instance"
    error_message = "Unexpected display name found."
  }

  assert {
    condition = google_monitoring_uptime_check_config.http.monitored_resource[0].labels.host == "4.4.4.4"
    error_message = "Unexepected host IP found"
  }
}

And run that:

% terraform test          
test.tftest.hcl... in progress
  run "deployment_test"... pass
test.tftest.hcl... tearing down
test.tftest.hcl... pass

Success! 1 passed, 0 failed.