unit-testing - 如何用reflect测试方法?

标签 unit-testing go

我有一个 Sync() 方法可以覆盖在环境中设置的 Config 字段值。 环境变量名称是通过下划线和大写名称从配置字段派生的。例如。 AppName会有一个对应的环境变量APP_NAME

请帮我测试以下情况。有复杂的东西,比如 https://golang.org/pkg/reflect/#Value.Set :

Set assigns x to the value v. It panics if CanSet returns false. As in Go, x's value must be assignable to v's type.

所以我不知道如何测试这个案例?

import (
    "encoding/json"
    "errors"
    "fmt"
     "os"
    "path/filepath"
    "reflect"
    "strconv"
    "strings"
    "github.com/BurntSushi/toml"
    "github.com/fatih/camelcase"
    "gopkg.in/yaml.v2"
)

type Config struct {
    AppName   string 
    BaseURL   string 
    Port      int    
    Verbose   bool   
    StaticDir string 
    ViewsDir  string 
}

func (c *Config) Sync() error {
    cfg := reflect.ValueOf(c).Elem()
    cTyp := cfg.Type()

    for k := range make([]struct{}, cTyp.NumField()) {
        field := cTyp.Field(k)

        cm := getEnvName(field.Name)
        env := os.Getenv(cm)
        if env == "" {
            continue
        }
        switch field.Type.Kind() {
        case reflect.String:
            cfg.FieldByName(field.Name).SetString(env)
        case reflect.Int:
            v, err := strconv.Atoi(env)
            if err != nil {
                return fmt.Errorf("loading config field %s %v", field.Name, err)
            }
            cfg.FieldByName(field.Name).Set(reflect.ValueOf(v))
        case reflect.Bool:
            b, err := strconv.ParseBool(env)
            if err != nil {
                return fmt.Errorf("loading config field %s %v", field.Name, err)
            }
            cfg.FieldByName(field.Name).SetBool(b)
        }

    }
    return nil
}

最佳答案

如果您想在调用 Sync 后测试对 Cofig 所做的更改,请在您的测试中定义一个设置环境的函数:

func SetTestEnv(key, value string) error; err != nil {
    if err := os.Setenv(key, value string) {
        return err
    }
    return nil
}

现在,您可以测试 Sync 函数,创建测试配置,使用上述方法初始化测试环境,并在配置值上调用 Syncstrconv 专门针对失败的转换定义了 NumError。你可以利用它:

func TestSync(t *testing.T) {
    c : Config{ 
        // initialize config, or do it through another method
        // e.g. func InitConfig(...) *Config {..}
    }

    // set the environment
    SetTestEnv("APP_NAME", "app name")
    SetTestEnv("BASE_URL", "base url")
    SetTestEnv("PORT", "port number") // will cause error
    // etc..

    if err := c.Sync(); err != nil {
        e, ok := err.(*strconv.NumError)
        if !ok {
            t.Errorf("Unexpected error")
        } else if e.Err != strconv.ErrSyntax { // check specifically for expected syntax error
            t.Errorf("Expected conversion to fail")
        }

    }

    SetTestEnv("PORT", "1000") // correct port number

    if err := c.Sync(); err != nil {
        t.Errorf("Unexpected error in Sync: %v", err)
    }
}

由于您确保使用类型开关以正确的值类型调用 Set,因此不应有任何原因导致 panic 发生。

关于unit-testing - 如何用reflect测试方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38299819/

相关文章:

vim - youcompleteme GoToDefinition 命令为 golang

go - 忽略 librd kafka 中的测试

reflection - Golang - 扫描所有类型的结构

if-statement - Golang - 使用框架时在 "if"语句后提供返回

c# - 如何保证异步方法继续在另一个线程上运行?

ios - iOS单元测试范围- Sonar 报告-xccov

php - 测试 Facade 时无法重新声明::shouldReceive()

opengl - 如何使用 openGL 的 golang 绑定(bind)定义 gl.DrawBuffers COLOR_ATTACHMENTi

c# - 在 VS 测试项目中维护单元测试方法之间的上下文

objective-c - 模拟 CLLocationManager (swift) 用于测试