funcTestInvokeByName(t *testing.T) { e := &Employee{"1", "Mike", 30} // 按名字获取成员 t.Logf("Name:value(%[1]v),Type(%[1]T)", reflect.ValueOf(*e).FieldByName("Name")) if nameField, ok := reflect.TypeOf(*e).FieldByName("Name"); !ok { t.Error("Failed to get 'Name' field.") } else { t.Log("Tag:format", nameField.Tag.Get("format")) } reflect.ValueOf(e).MethodByName("UpdateAge").Call([]reflect.Value{reflect.ValueOf(1)}) t.Log("Updated Age:", e) /** 运行结果: === RUN TestInvokeByName TestInvokeByName: reflect_test.go:28: Name:value(Mike),Type(reflect.Value) TestInvokeByName: reflect_test.go:32: Tag:format normal TestInvokeByName: reflect_test.go:35: Updated Age: &{1 Mike 1} --- PASS: TestInvokeByName (0.00s) */ }
Struct Tag:
1 2 3 4
type BasicInfo struct { Name string`json:"name"` Age int`json:"age"` }
访问Struct:
1 2 3 4
if nameField, ok := reflect.TypeOf(*e).FieldByName("Name"); !ok { t.Error("Failed to get 'Name' field.") } else { t.Log("Tag:format", nameField.Tag.Get("format")) }
// func (v Value) Elem() Value // Elem returns the value that the interface v contains or that the pointer v points to. // It panics if v's Kind is not Interface or Ptr. // It returns the zero Value if v is nil.
if reflect.TypeOf(st).Kind() != reflect.Ptr { return errors.New("the first param should be a pointer to the struct type.") } // Elem() 获取指针指向的值 if reflect.TypeOf(st).Elem().Kind() != reflect.Struct { return errors.New("the first param should be a pointer to the struct type.") }
if settings == nil { return errors.New("settings is nil.") }
var ( field reflect.StructField ok bool )
for k, v := range settings { if field, ok = (reflect.ValueOf(st)).Elem().Type().FieldByName(k); !ok { continue } if field.Type == reflect.TypeOf(v) { vstr := reflect.ValueOf(st) vstr = vstr.Elem() vstr.FieldByName(k).Set(reflect.ValueOf(v)) }
} returnnil }
funcTestFillNameAndAge(t *testing.T) { settings := map[string]interface{}{"Name": "Mike", "Age": 30} e := Employee{} if err := fillBySettings(&e, settings); err != nil { t.Fatal(err) } t.Log(e) c := new(Customer) if err := fillBySettings(c, settings); err != nil { t.Fatal(err) } t.Log(*c) /** 运行结果: === RUN TestFillNameAndAge TestFillNameAndAge: fiexible_reflect_test.go:69: { Mike 30} TestFillNameAndAge: fiexible_reflect_test.go:74: { Mike 30} --- PASS: TestFillNameAndAge (0.00s) */ }
go get -u github.com/smartystreets/goconvey/convey
启动 WEB UI :
$GOPATH/bin/goconvey
1 2 3 4 5 6 7 8 9 10 11 12
funcTestSpec(t *testing.T) { convey.Convey("Given 2 even numbers", t, func() { a := 2 b := 4 convey.Convey("When add the two numbers", func() { c := a + b convey.Convey("Then the result is still even", func() { convey.So(c%2, convey.ShouldEqual, 0) }) }) }) }
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13
$ go test -v bdd_spec_test.go === RUN TestSpec
Given 2 even numbers When add the two numbers Then the result is still even ✔
1 total assertion
--- PASS: TestSpec (0.00s) PASS ok command-line-arguments 0.006s
funcrunTask(id int)string { time.Sleep(10 * time.Millisecond) return fmt.Sprintf("the result is from %d", id) }
funcFirstResponse()string { numOfRunner := 10 ch := make(chanstring) // 非缓冲channel for i := 0; i < numOfRunner; i++ { gofunc(i int) { ret := runTask(i) ch <- ret }(i) } return <-ch }
funcTestFirstResponse(t *testing.T) { t.Log(FirstResponse()) /** 第一次运行结果: === RUN TestFirstResponse TestFirstResponse: first_response_test.go:27: the result is from 0 --- PASS: TestFirstResponse (0.01s) */ /** 第二次运行结果: === RUN TestFirstResponse TestFirstResponse: first_response_test.go:27: the result is from 3 --- PASS: TestFirstResponse (0.01s) */ }
因为协程的调度机制,所以返回结果不一样。
但这样是存在很大的问题,修改TestFirstResponse:
1 2 3 4 5 6 7 8 9 10 11 12 13
funcTestFirstResponse(t *testing.T) { t.Log("Before:", runtime.NumGoroutine()) // 获取协程数量 t.Log(FirstResponse()) time.Sleep(time.Second * 1) t.Log("After:", runtime.NumGoroutine()) // 获取协程数量 /** 运行结果: === RUN TestFirstResponse TestFirstResponse: first_response_test.go:28: Before: 2 TestFirstResponse: first_response_test.go:29: the result is from 6 TestFirstResponse: first_response_test.go:30: After: 11 --- PASS: TestFirstResponse (0.01s) */ }
funcrunTask(id int)string { time.Sleep(10 * time.Millisecond) return fmt.Sprintf("the result is from %d", id) }
funcAllResponse()string { numOfRunner := 10 ch := make(chanstring) // 非缓冲channel for i := 0; i < numOfRunner; i++ { gofunc(i int) { ret := runTask(i) ch <- ret }(i) }
finalRet := "" for i := 0; i < numOfRunner; i++ { finalRet += <-ch + "\n" }
return finalRet }
funcTestFirstResponse(t *testing.T) { t.Log(AllResponse()) /** 运行结果: === RUN TestFirstResponse TestFirstResponse: all_done_test.go:33: the result is from 9 the result is from 0 the result is from 2 the result is from 7 the result is from 4 the result is from 6 the result is from 1 the result is from 5 the result is from 8 the result is from 3 --- PASS: TestFirstResponse (0.01s) */ }
funcTestSyncPoolMultiGoroutine(t *testing.T) { pool := sync.Pool{ New: func()interface{} { fmt.Println("Create a new object.") return10 }, }
pool.Put(100) pool.Put(100) pool.Put(100)
var wg sync.WaitGroup
for i := 0; i < 10; i++ { wg.Add(1) gofunc() { t.Log(pool.Get()) wg.Done() }() } wg.Wait() /** 运行结果: === RUN TestSyncPoolMultiGoroutine TestSyncPoolMultiGoroutine: sync_pool_test.go:59: 100 Create a new object. TestSyncPoolMultiGoroutine: sync_pool_test.go:59: 10 Create a new object. TestSyncPoolMultiGoroutine: sync_pool_test.go:59: 10 TestSyncPoolMultiGoroutine: sync_pool_test.go:59: 100 Create a new object. Create a new object. TestSyncPoolMultiGoroutine: sync_pool_test.go:59: 10 Create a new object. Create a new object. Create a new object. TestSyncPoolMultiGoroutine: sync_pool_test.go:59: 100 TestSyncPoolMultiGoroutine: sync_pool_test.go:59: 10 TestSyncPoolMultiGoroutine: sync_pool_test.go:59: 10 TestSyncPoolMultiGoroutine: sync_pool_test.go:59: 10 TestSyncPoolMultiGoroutine: sync_pool_test.go:59: 10 --- PASS: TestSyncPoolMultiGoroutine (0.00s) */ }
var LessThanTwoError = errors.New("n should be not less than 2") var LargerThenHundredError = errors.New("n should be not larger than 100")
funcGetFibonacci(n int)([]int, error) { if n < 2 { returnnil, LessThanTwoError }
if n > 100 { returnnil, LargerThenHundredError }
fibList := []int{1, 2}
for i := 2; i < n; i++ { fibList = append(fibList, fibList[i-2]+fibList[i-1]) } return fibList, nil }
funcTestGetFibonacci(t *testing.T) { // 如果有错误进行错误输出 if v, err := GetFibonacci(-10); err != nil { // 假如调用者需要判断错误的就比较简单了 if err == LessThanTwoError { fmt.Println("It is less.") } t.Error(err) } else { t.Log(v) } /** 运行结果 === RUN TestGetFibonacci It is less. TestGetFibonacci: err_test.go:36: n should be not less than 2 --- FAIL: TestGetFibonacci (0.00s) */ }
funcTestClient(t *testing.T) { var p Programmer p = new(GoProgrammer) t.Log(p.WriteHelloWorld()) /** 运行结果: === RUN TestClient TestClient: interface_test.go:19: Hello World --- PASS: TestClient (0.00s) */ }
funcTestStringFn(t *testing.T) { s := "A,B,C" // 字符串切割 parts := strings.Split(s, ",") for _, part := range parts { t.Log(part) } // 字符串拼接 t.Log(strings.Join(parts, "-")) /** 运行结果: === RUN TestStringFn TestStringFn: string_fun_test.go:12: A TestStringFn: string_fun_test.go:12: B TestStringFn: string_fun_test.go:12: C TestStringFn: string_fun_test.go:14: A-B-C --- PASS: TestStringFn (0.00s) */ }