如何Mock Terraform函数?Terratest测试timestamp()遇阻求助
问题描述
我正在学习Terraform,用Terratest做测试时,没法Mock Terraform的timestamp()这类内置函数。试过用monkey库打桩,但完全没用。以下是复现代码:
main.tf
locals { creation_time = formatdate("YYYYMMDDhhmmss", timestamp()) }
outputs.tf
output "CreationDate" { value = local.creation_time description = "Bla bla bla" }
./tests/main_test.go
package study import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/terratest/modules/terraform" "bou.ke/monkey" ) func TestTerraformTimestamp(t *testing.T) { t.Parallel() terraformOptions := &terraform.Options{ TerraformDir: "../", } monkey.Patch(time.Now, func() time.Time { return time.Date(2022, 12, 8, 23, 59, 1, time.UTC) }) defer monkey.Unpatch(time.Now) defer terraform.Destroy(t, terraformOptions) terraform.InitAndApply(t, terraformOptions) output := terraform.Output(t, terraformOptions, "CreationDate") assert.Equal(t, "20221208235901", output) }
运行步骤:
go mod init study go mod tidy cd tests go test
我希望能Mock Terraform的内置函数,断言输出值,验证Terraform模块功能是否符合预期,有没有可行的解决办法?
解决方案
为什么原来的方法无效?
Terratest是通过调用外部Terraform二进制进程来执行初始化、应用等操作的,你在Go代码里用monkey patch修改的time.Now()只会影响当前的Go测试进程,完全不会影响独立运行的Terraform进程。Terraform的timestamp()函数是在自己的进程里获取系统时间,所以打桩根本碰不到它。
最实用的解决办法:变量注入
把依赖内置函数的逻辑抽成Terraform变量,生产环境用默认值(调用timestamp()),测试时传入固定值覆盖。这样既不影响生产代码的正常逻辑,又能在测试中完全控制输出。
修改Terraform代码
更新main.tf,新增变量并替换硬编码的timestamp():variable "creation_time_override" { type = string description = "Override creation time for testing purposes" default = formatdate("YYYYMMDDhhmmss", timestamp()) } locals { creation_time = var.creation_time_override }修改测试代码
在terraform.Options里通过Vars传入固定的测试值:func TestTerraformTimestamp(t *testing.T) { t.Parallel() testTime := "20221208235901" terraformOptions := &terraform.Options{ TerraformDir: "../", Vars: map[string]interface{}{ "creation_time_override": testTime, }, } defer terraform.Destroy(t, terraformOptions) terraform.InitAndApply(t, terraformOptions) output := terraform.Output(t, terraformOptions, "CreationDate") assert.Equal(t, testTime, output) }
其他备选方案(适合复杂场景)
如果你的模块逻辑更复杂,没法直接用变量覆盖,比如依赖多个内置函数或数据源的时间,可以考虑:
- 使用Terraform的
external数据源:编写一个简单的脚本,测试时返回固定时间,生产环境返回系统时间。但这种方式比变量注入繁琐,只适合特殊场景。 - 避免在模块中直接依赖
timestamp():把时间相关的逻辑移到调用方,由外部传入时间值,让模块更具可测试性。
内容的提问来源于stack exchange,提问作者lucAlucard
相关产品推荐
相关产品推荐

