2016-07-11 10 views
0

Ich habe eine Methode Sync(), die Config Feldwerte überschreibt, die in der Umgebung festgelegt sind. Die Namen der Umgebungsvariablen werden durch Unterstreichen von Konfigurationsfeldern abgeleitet und der Name wird in Großbuchstaben dargestellt. Z.B. AppName hat eine entsprechende Umgebungsvariable APP_NAMEWie man Methode mit reflektiertem prüft?

Bitte helfen Sie mir, die folgenden Fälle zu testen. Es gibt komplexe Dinge wie https://golang.org/pkg/reflect/#Value.Set:

Set x auf den Wert v zuweist Es gerät in Panik, wenn CanSet false zurückgibt.. Wie in Go, muss der Wert von x dem Typ von v zugewiesen werden.

Also weiß ich nicht, wie man diesen Fall prüft?

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 
} 

Antwort

1

Wenn Sie Änderungen an Cofig testen wollen nach Sync Aufruf in Ihren Tests eine Funktion definieren, die die Umwelt setzt:

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

Jetzt in Sie Funktion für Sync testen, erstellen Sie eine Test-Config , initialisieren Sie die Testumgebung mit der obigen Methode und rufen Sie den Konfigurationswert Sync auf. strconv definiert NumError speziell für fehlgeschlagene Konvertierungen. Sie können Gebrauch davon machen:

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) 
    } 
} 

Da Sie Set sind gewährleistet mit dem richtigen Werttyp mit Typ-Schalter genannt wird, gibt es keinen Grund zur Panik sein sollte auftreten.

+0

Ich möchte testen, ob Code funktioniert, wenn ein Fehler in 'v, err: = strconv.Atoi (env)' innerhalb der Sync() -Methode existiert –

+1

Wie oben erwähnt 'SetTestEnv (" PORT "," any string ")' setzt die Portnummer auf eine Zeichenkette, die nicht in eine Zahl umgewandelt werden kann. In diesem Fall würde der Aufruf von 'Sync' ein Fehler sein, den der erste' if' in der Testfunktion testet. – abhink

+1

hinzugefügt spezifische Fehlerprüfung Details – abhink

Verwandte Themen