如何用反射测试方法?

I have a method Sync() that overrides Config field's values that are set in the environment. The environment variable names are derived from config fields by underscoring, and uppercasing the name. E.g. AppName will have a corresponding environment variable APP_NAME

Please help me to test the following cases. There are complex things like 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.

So I don't know how to test this case?

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
}

If you want to test changes made to Cofig after calling Sync, in your tests define a function that sets the environment:

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

Now in you test function for Sync, create a test config, initialize test environment using the above method and call Sync on the config value. strconv defines NumError specifically for failed conversions. You can make use of that:

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

Since you are ensuring Set is called with correct value type using type switches, there should not be any cause for panic to occur.