如何解决我应该如何测试处理设置大量环境配置/操作系统参数的函数?
我编写了一个 Go 应用程序,所有的包都有完整的测试覆盖。我正在编写我的 main
包 - 它将处理 main()
函数中应用程序的所有初始设置 - 该函数当前读取 14 个环境变量,然后设置相关变量在应用程序中。代码的简单概述是:
func main() {
myStruct1 := privatePackage.myStructType{}
myStruct2 := publicPackage.otherStructType{}
if config1 := os.Getenv("CONfig_FOO"); config1 != "" {
myStruct1.attribute1 = config1
}
// ....
if config14 := os.Getenv("CONfig_BAR"); config14 != "" {
myStruct2.attribute5 = config14
}
}
当我测试单元环境变量/操作系统参数时,我通常只是直接在测试函数中设置环境变量 - 就像:
func TestMyArgument(t *testing.T) {
os.Setenv("CONfig_BAZ","apple")
//Invoke function that depends on CONfig_BAZ
//Assert that expected outcome occurred
}
我几乎总是使用表驱动的测试,所以上面的代码片段是一个简化的例子。
问题是我的 main()
函数接受了 14 个(并且不断增长的)环境变量,而一些环境变量本质上是枚举(因此有少量有效选项 - 例如有少量数据库驱动程序可供选择),其他环境变量几乎具有无限的潜在值。那么我如何才能有效地涵盖所有(或足够多的)潜在配置的排列?
编辑:部署此应用程序后,它将进入 K8s 集群。其中一些变量是将从安全存储中提取的秘密。使用 JSON 文件是不可行的,因为某些值需要轻松加密/更改。 此外,使用 JSON 文件需要我存储此文件并在成百上千个正在运行的 pod 之间共享它——然后这个存储将充当故障点。 澄清一下,这个问题与 env vars VS 配置文件无关;这个问题是关于当有大量可配置变量时进行测试的最佳方法 - 每个变量都有大量的潜在值 - 导致数千个可能的配置排列。在这种情况下,我如何保证足够的测试覆盖率?
解决方法
除了一两个,我不认为使用环境变量是正确的
方法,除非它需要(用 os/exec
调用)。相反,会
最好从配置文件中读取。以下是 JSON 示例:
{
"CONFIG_BAR": "east","CONFIG_BAZ": "south","CONFIG_FOO": "north"
}
package main
import (
"encoding/json"
"fmt"
"os"
)
func main() {
f,e := os.Open("file.json")
if e != nil {
panic(e)
}
defer f.Close()
var s struct { CONFIG_BAR,CONFIG_BAZ,CONFIG_FOO string }
json.NewDecoder(f).Decode(&s)
// {CONFIG_BAR:east CONFIG_BAZ:south CONFIG_FOO:north}
fmt.Printf("%+v\n",s)
}
TOML 也是不错的选择。
,@Steven Penny 是对的:使用 json
- 使用reflect可以让代码更简单:
package main
import (
"encoding/json"
"fmt"
"os"
"reflect"
"strconv"
)
type MyStructType struct {
Attribute1 string `json:"CONFIG_FOO"`
Attribute2 string `json:"CONFIG_BAZ"`
Attribute3 int `json:"CONFIG_BAR"`
}
func NewMyStructTypeFormEnv() *MyStructType {
myStructType := MyStructType{}
ReflectMyStructType(&myStructType)
fmt.Println("myStructType is now",myStructType)
return &myStructType
}
func NewMyStructTypeFormJson() *MyStructType {
myStructType := MyStructType{}
f,e := os.Open("file.json")
if e != nil {
panic(e)
}
defer f.Close()
json.NewDecoder(f).Decode(&myStructType)
fmt.Println("myStructType is now",myStructType)
return &myStructType
}
func ReflectMyStructType(ptr interface{}){
v := reflect.ValueOf(ptr).Elem()
fmt.Printf("%v\n",v.Type())
for i := 0; i < v.NumField(); i++ {
env_str := v.Type().Field(i).Tag.Get("json")
if(env_str == ""){continue}
if config := os.Getenv(env_str); config != "" {
if v.Field(i).Kind() == reflect.String{
v.Field(i).SetString(config)
}else if v.Field(i).Kind() == reflect.Int{
iConfig,_ := strconv.Atoi(config)
v.Field(i).SetInt(int64(iConfig))
}
}
}
}
func main() {
NewMyStructTypeFormJson()
os.Setenv("CONFIG_FOO","apple")
os.Setenv("CONFIG_BAZ","apple")
os.Setenv("CONFIG_BAR","1")
NewMyStructTypeFormEnv()
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。