微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

我应该如何测试处理设置大量环境配置/操作系统参数的函数?

如何解决我应该如何测试处理设置大量环境配置/操作系统参数的函数?

我编写了一个 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 举报,一经查实,本站将立刻删除。