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

我已经编写了一个Go应用程序,所有软件包都具有完整的测试覆盖率。我正在编写我的包 - 它将处理函数中应用程序的所有初始设置 - 此函数当前读取14个环境变量,然后在应用程序中设置相关变量。代码的简单概述如下:mainmain()


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

    }

}

当我测试单元 env 变量/OS 参数时,我通常只直接在测试函数中设置 env 变量 - 所以像这样:


func TestMyArgument(t *testing.T) {

    os.Setenv("CONFIG_BAZ", "apple")


    //Invoke function that depends on CONFIG_BAZ

    //Assert that expected outcome occurred

}

我几乎总是使用表驱动的测试,所以上面的代码片段是一个简化的例子。


问题在于,我的函数接收了 14 个(并且还在增长)env 变量,虽然一些 env 变量本质上是枚举(因此有少量有效选项 - 例如,有少量数据库驱动程序可供选择),但其他 env 变量具有几乎无限的潜在值。那么,如何有效地覆盖潜在配置的所有(或足够多的)排列呢?main()


编辑:部署此应用程序后,它将进入K8s集群。其中一些变量是从安全存储中提取的机密。使用 JSON 文件是不可行的,因为某些值需要轻松加密/更改。此外,使用JSON文件需要我存储此文件并在数百/数千个正在运行的 Pod 之间共享它 - 然后此存储将充当故障点。为了澄清,这个问题不是关于env vars VS配置文件;这个问题是关于当有大量可配置变量时进行测试的最佳方法 - 每个变量都有大量的潜在值 - 导致数千个可能的配置排列。在这种情况下,如何保证足够的测试覆盖率?


冉冉说
浏览 134回答 2
2回答

天涯尽头无女友

@Steven Penny是对的:使用json使用refrebra可以使代码更简单:package mainimport (&nbsp; &nbsp; "encoding/json"&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "os"&nbsp; &nbsp; "reflect"&nbsp; &nbsp; "strconv")type MyStructType struct {&nbsp; &nbsp; Attribute1 string `json:"CONFIG_FOO"`&nbsp; &nbsp; Attribute2 string `json:"CONFIG_BAZ"`&nbsp; &nbsp; Attribute3 int `json:"CONFIG_BAR"`}func NewMyStructTypeFormEnv() *MyStructType {&nbsp; &nbsp; myStructType := MyStructType{}&nbsp; &nbsp; ReflectMyStructType(&myStructType)&nbsp; &nbsp; fmt.Println("myStructType is now", myStructType)&nbsp; &nbsp; return &myStructType}func NewMyStructTypeFormJson() *MyStructType {&nbsp; &nbsp; myStructType := MyStructType{}&nbsp; &nbsp; f, e := os.Open("file.json")&nbsp; &nbsp; if e != nil {&nbsp; &nbsp; &nbsp; &nbsp; panic(e)&nbsp; &nbsp; }&nbsp; &nbsp; defer f.Close()&nbsp; &nbsp; json.NewDecoder(f).Decode(&myStructType)&nbsp; &nbsp; fmt.Println("myStructType is now", myStructType)&nbsp; &nbsp; return &myStructType}func ReflectMyStructType(ptr interface{}){&nbsp; &nbsp; v := reflect.ValueOf(ptr).Elem()&nbsp; &nbsp; fmt.Printf("%v\n", v.Type())&nbsp; &nbsp; for i := 0; i < v.NumField(); i++ {&nbsp; &nbsp; &nbsp; &nbsp; env_str := v.Type().Field(i).Tag.Get("json")&nbsp; &nbsp; &nbsp; &nbsp; if(env_str == ""){continue}&nbsp; &nbsp; &nbsp; &nbsp; if config := os.Getenv(env_str); config != "" {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if v.Field(i).Kind() == reflect.String{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; v.Field(i).SetString(config)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }else if v.Field(i).Kind() == reflect.Int{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; iConfig,_ := strconv.Atoi(config)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; v.Field(i).SetInt(int64(iConfig))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}func main() {&nbsp; &nbsp; NewMyStructTypeFormJson()&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; os.Setenv("CONFIG_FOO", "apple")&nbsp; &nbsp; os.Setenv("CONFIG_BAZ", "apple")&nbsp; &nbsp; os.Setenv("CONFIG_BAR", "1")&nbsp; &nbsp; NewMyStructTypeFormEnv()}

弑天下

除了一两个之外,我不认为使用环境变量是正确的方法,除非需要它(调用)。相反,最好从配置文件中读取。下面是一个 JSON 示例:os/exec{&nbsp; &nbsp;"CONFIG_BAR": "east",&nbsp; &nbsp;"CONFIG_BAZ": "south",&nbsp; &nbsp;"CONFIG_FOO": "north"}package mainimport (&nbsp; &nbsp;"encoding/json"&nbsp; &nbsp;"fmt"&nbsp; &nbsp;"os")func main() {&nbsp; &nbsp;f, e := os.Open("file.json")&nbsp; &nbsp;if e != nil {&nbsp; &nbsp; &nbsp; panic(e)&nbsp; &nbsp;}&nbsp; &nbsp;defer f.Close()&nbsp; &nbsp;var s struct { CONFIG_BAR, CONFIG_BAZ, CONFIG_FOO string }&nbsp; &nbsp;json.NewDecoder(f).Decode(&s)&nbsp; &nbsp;// {CONFIG_BAR:east CONFIG_BAZ:south CONFIG_FOO:north}&nbsp; &nbsp;fmt.Printf("%+v\n", s)}TOML也是一个不错的选择。https://golang.org/pkg/encoding/jsonhttps://pkg.go.dev/github.com/pelletier/go-toml
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go