Golang 反射 && 单元测试

一.反射

 1 package reflecttest
 2 
 3 import (
 4     "fmt"
 5     "reflect"
 6 )
 7 
 8 // 语法:const [name] [type] = [value]
 9 // const 只能修饰int\float\string\bool作为常量
10 const ss string = "123"
11 const (
12     a = iota // a是0,往后依次递增1
13     b
14     c
15     d
16 )
17 
18 /*
19     反射:
20         1.反射可以在运行时动态获取变量的各种信息,比如变量的类型(type),类别(kind)
21         2.如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段、方法)
22         3.通过反射,可以修改变量的值,可以调用关联的方法
23         4.使用反射,需要import("reflect")
24         5.变量、interface{}、reflect.Value时可以相互转换的。
25 */
26 
27 func TestReflect(b interface{}) {
28     // 1.将interface{}专成reflect.Value
29     rVal := reflect.ValueOf(b)
30 
31     // 2.将reflect.Value转成interface{}
32     iVal := rVal.Interface()
33 
34     // 3.获取kind常量
35     fmt.Printf("kind=%v, type=%T\n", rVal.Kind(), rVal.Kind()) // reflect.Kind
36 
37     // 4.将interface{}专程原来的变量类型
38     switch iVal.(type) {
39     case int:
40         fmt.Println("int")
41         // 4.转reflect.Type
42         reflect.ValueOf(iVal.(int)) // 返回的就是:reflect.Type
43         rVal.Type()                 // 返回的就是:reflect.Type
44         fmt.Printf("kind=%v\n", rVal.Type().Kind())
45     default:
46         fmt.Println("err type!")
47     }
48 
49 }
50 
51 func TestStructReflect() {
52     var ss string = "Tom"
53     TestElem := func(b interface{}) {
54         // 1.读取reflectValue
55         rVal := reflect.ValueOf(b)
56         // 2.Kind
57         fmt.Println("Kind=", rVal.Kind())
58         // 3.设置值.
59         //   通过反射来修改变量,注意当使用SetXxx方法来设置时,需要通过对应的指针类型来完成,这样才能改变传入变量的值,同时需要使用到reflect.Value.Elem()方法
60         //   因为rVal是指针,我们的目的是修改指针指向的内容.这里rVal.Elem()的作用是,将rVal包装成可修改指针指向内容值的reflect.Value返回
61         rVal.Elem().SetString("123456789")
62         // rVal.SetInt(1)
63     }
64     fmt.Println(&ss)
65     TestElem(&ss)
66     fmt.Println(&ss)
67     fmt.Println(ss)
68 }
  1 package reflecttest
  2 
  3 import (
  4     "fmt"
  5     "reflect"
  6 )
  7 
  8 type Monster struct {
  9     Name  string  `json:"name"`
 10     Age   int     `json:"age"`
 11     Score float32 `json:"score"`
 12     Sex   string
 13 }
 14 
 15 /* 显示值 */
 16 func (self *Monster) Print() {
 17     fmt.Println("-----start--------")
 18     fmt.Println(*self)
 19     fmt.Println("-----end--------")
 20 }
 21 
 22 /* 返回两个数的和  */
 23 func (self *Monster) GetSum(a int, b int) int {
 24     return a + b
 25 }
 26 
 27 /* 赋值 */
 28 func (self *Monster) SetValue(name string, age int, score float32, sex string) {
 29     self.Name = name
 30     self.Age = age
 31     self.Score = score
 32     self.Sex = sex
 33 }
 34 
 35 // 反射字段标签的用法
 36 func TestStructFieldTag(b interface{}) {
 37     // 获取reflect.Type
 38     typ := reflect.TypeOf(b)
 39     typ1 := reflect.TypeOf(b)
 40     // 获取reflect.Value
 41     val := reflect.ValueOf(b)
 42     val1 := reflect.ValueOf(b)
 43     // 获取对应的类型
 44     kd := val.Kind()
 45     if kd == reflect.Ptr {
 46         val = val.Elem()
 47         kd = val.Kind()
 48         typ = val.Type()
 49     }
 50     // 如果不是结构体就退出
 51     if kd != reflect.Struct {
 52         fmt.Println("传入的值必须是struct类型.")
 53         return
 54     }
 55 
 56     // 获取该结构体有几个字段
 57     num := val.NumField()
 58     fmt.Printf("%v 结构体有%v个字段.\n", typ, num)
 59     // 获取每个字段的值,以及字段设定的标签
 60     for i := 0; i < num; i++ {
 61         fmt.Printf("字段%v,值=%v\n", typ.Field(i).Name, val.Field(i))
 62         // 注意:获取字段标签值,需要通过reflect.Type来获取
 63         tagVal := typ.Field(i).Tag.Get("json")
 64         if tagVal != "" {
 65             fmt.Printf("字段'%v',标签=%v\n", typ.Field(i).Name, tagVal)
 66         }
 67         if typ.Field(i).Name == "Name" {
 68             // 修改字段值
 69             val.Field(i).SetString("ReName")
 70         }
 71     }
 72 
 73     // 获取该结构体有多少个方法
 74     num = val.NumMethod()
 75     fmt.Printf("%v 结构体有%v个方法.\n", typ, num)
 76     num = typ1.NumMethod()
 77     fmt.Printf("%v 结构体有%v个方法.\n", typ1, num)
 78 
 79     // 调用结构体的方法,并传参数
 80     var params []reflect.Value
 81     // reflecttest.Monster 结构体有0个方法.
 82     params = append(params, reflect.ValueOf(1))
 83     // *reflecttest.Monster 结构体有3个方法.
 84     params = append(params, reflect.ValueOf(2))
 85     res := val1.MethodByName("GetSum").Call(params)
 86     // 调用结构体中的'GetSum()'=3 , 返回的类型是[]reflect.Value
 87     fmt.Printf("调用结构体中的'GetSum()'=%v , 返回的类型是%T\n", res[0], res)
 88 
 89 }
 90 
 91 // 函数适配器:给要执行的函数加日志
 92 func TestReflectFunc(function, f1 interface{}) {
 93 
 94     funVal := reflect.ValueOf(function).Elem()
 95     funTyp := funVal.Type()
 96 
 97     packFunc := func(in []reflect.Value) (result []reflect.Value) {
 98         fmt.Println("---begin---")
 99         result = reflect.ValueOf(f1).Call(in)
100         fmt.Println("---end---")
101         return result
102     }
103 
104     v := reflect.MakeFunc(funTyp, packFunc)
105     funVal.Set(v)
106 
107 }
108 
109 func TestReflect1() {
110     tfunc := func(a int, b int) int {
111         return a + b
112     }
113 
114     TestReflectFunc(&tfunc, tfunc)
115     c := tfunc(1, 2)
116     fmt.Println(c)
117 
118     obj := Monster{}
119     obj.SetValue("Tom", 19, 102, "Man")
120     TestStructFieldTag(&obj)
121     fmt.Println(obj)
122 }

二.单元测试

 1 package main
 2 
 3 import (
 4     "testing"
 5 )
 6 
 7 func TestAddUpper(t *testing.T) {
 8     /*
 9         注意细节:
10             1.测试文件名必须"_test.go"结尾.一般用测试单元文件的名加上后缀
11             2.测试用例函数必须以Test开头,一般用"Test+被测试的函数名"
12             3.Testddpper(t *testing.T) 的形参类型必须是"t *testing.T"
13             4.一个测试用例文件中可以有多个测试用例函数
14             5.运行测试用例指令
15                 go test      // 如果运行正确,无日志,错误时,会输出日志
16                 go test -v    // 运行正确错误,都输出日志
17                 go test [测试单元文件名main_test.go] [测试的原文件main.go]    // 测试指定的测试单元
18                 go test -v -test.run [具体测试的方法TestAddUpper]            // 测试具体单个方法
19             6.当出现错误时,可以使用t.Fatalf 来格式化输出错误信息,并退出程序
20             7.t.Logf方法可以输出相应的日志
21             8.测试用例函数,并没有放在main函数中也执行了,这就是测试用例的方便之处
22             9,PASS表示测试用例运行成功,FAIL表示测试用例运行失败
23 
24     */
25     sum := TestUnit(10)
26     if sum != 55 {
27         t.Fatalf("TestUnit(10) 执行错误,期望值=%v,实际值=%v\n", 55, sum)
28     }
29     t.Logf("TestUnit(10) 执行正确")
30 }

 

posted @ 2023-09-19 08:32  看一百次夜空里的深蓝  阅读(37)  评论(0编辑  收藏  举报