2016-07-11 60 views
0

我有一個方法Sync(),它將覆蓋在環境中設置的Config字段的值。 環境變量名稱通過下劃線從配置字段派生,並將名稱大寫。例如。 AppName將具有相應的環境變量APP_NAME如何用反映測試方法?

請幫我測試以下情況。有複雜的東西,如https://golang.org/pkg/reflect/#Value.Set

設置將x賦值給值v。如果CanSet返回false,則會發生混亂。和 一樣,x的值必須可以賦值給v的類型。

所以我不知道如何測試這種情況?

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 
} 

回答

1

如果你想打電話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被稱爲使用正確的值類型類型的開關,不應該有任何原因出現恐慌。

+0

我想測試代碼是否在Sync()方法中的'v,err:= strconv.Atoi(env)'中出現錯誤 –

+1

如上所述,SetTestEnv(「PORT」,「any string 「)'將端口號設置爲無法轉換爲數字的字符串。在這種情況下,調用'Sync'會導致測試函數中第一個'if'正在測試的錯誤。 – abhink

+1

添加了特定的錯誤檢查詳細信息 – abhink