Golang 有很多优秀的开源框架 能够帮我们很方便的写出测试代码 来模拟不同的场景。
gomonkeygomonkey 是一种很简单的mock框架 基于打桩函数的方式来进行mock不同的函数调用 从而实现不同的场景的mock。该代码库地址 https://github.com/agiledragon/gomonkey
我们要测试一个函数 而这个函数还调用了其他几个函数 在测试代码中 我们需要有代码调用上下文才能够使调用子函数成功 但是通常 调用上下文有可能很复杂 没有办法将所有依赖的环境上下文配置好 比如 配置文件的设定 数据库的设定 http/RPC的设定以及第三方库的设定。就是说 变成上下文是如此的复杂 几乎无法将所有的上下文配置好。
比较简单的办法就是避免的办法 就是避免真是的子函数调用 而是采用打桩的办法 模拟子函数的调用 返回不同的值来测试不同的场景。在后面我们给出一些例子来介绍具体的用法。
ApplyFunc 用法import( fmt func TestFunc(num1 int, num2 int) int { res : CompareInt(num1, num2) fmt.Println( CompareInt return , res) return resfunc CompareInt(num1 int, num2 int) int { if num1 num2 { return 0 }else if num1 num2 { return 1 }else { return -1}
如下的代码 采用ApplyFunc来测试CompareInt函数
import ( fmt . github.com/agiledragon/gomonkey . github.com/smartystreets/goconvey/convey reflect testing func Test_CompareInt(t *testing.T) { Convey( CompareInttest t, func() { // ApplyFunc 的第一个参数是待测试的函数名字 // 第二个参数是待测试函数的函数原型 // 这里模拟返回值是0 的情况 我们还可以返回1或者-1 patch : ApplyFunc(CompareInt, func(_ int, _ int) (int) { return 0 result : TestFunc 1 1 So(result, ShouldEqual, 0) fmt.Println( CompareInt test success )
上面的例子是最简单情况 TestFunc调用函数CompareInt, 我们测试TestFunc的时候 要先mock出来CompareInt 采用ApplyFunc 输入函数名字和待测试函数原型就可以打桩 返回我们需要测试的场景。
ApplyMethod 用法ApplyFunc对于稍微复杂一点的场景 例如 interface{} 接口 就不灵了 还好gomonkey提供了另外一个函数ApplyMethod来实现这一场景。
import( fmt type Person interface { Interesting(product string) booltype Student strut {func (s *Student) Interesting(prodName string) bool{ if prodName pen { return true } else { return falsefunc testFunc(prodName string) bool{ st : Student{} result : st.Interesting(prodName) if false result { fmt.Println( Student like product , prodName) return result}
ApplyMethod的用法和ApplyFunc的用法类似 第一个参数代表struct的类型 第二个参数是待测试函数的名字的字符串 第三个参数是待测试函数的原型。
import ( fmt . github.com/agiledragon/gomonkey . github.com/smartystreets/goconvey/convey reflect testing func Test_testFunc(t *testing.T) { stu : Student{} Convey( testFunc success t, func() { patch : ApplyMethod(reflect.TypeOf(stu), testFunc , func(_ string) (bool) { return true result : TestFunc pen So(result, ShouldEqual, true) Convey( testFunc fail t, func() { patch : ApplyMethod(reflect.TypeOf(stu), testFunc , func(_ string) (bool) { return false result : TestFunc book So(result, ShouldEqual, false) fmt.Println( CompareInt test success )}
上面的例子 函数testFunc传入一个字符串 如果是“pen”就返回true 否则false 我们经过ApplyMethod来mock interface。
httptestHttp handler是golang代码里面很重要的一部分 它是http调用的入口函数 在golang的官方代码包里面包含了httptest 它可以很方便的帮我们测试相关的代码。
import( net/http encoding/json type Person struct { Name string Age inthttp.HandleFunc( /get_host_info , GetHostInfoHandler)func GetHostInfoHandler(w http.ResponseWriter, r *http.Request) { bytes, _: ioutil.ReadAll(r.Body) if len(bytes) 0 { w.WriteHeader(http.StatusBadRequest) return request : Person{} err json.Unmarshal(bytes, request) if err ! nil { w.WriteHeader(http.StatusBadRequest) return fmt.Println( Request paramter: % v , request) w.WriteHeader(http.StatusOK) w.Header().Set( Content-Type , application/json ) io.WriteString(w, { Code : 0, Message : Success } )}
httptest主要就是mock出来一个http.Request, 以及一个http.ResponseWriter, 对于传入的参数以及返回给调用者的response 可以根据所测试的函数进行适配。
import ( fmt . github.com/agiledragon/gomonkey . github.com/smartystreets/goconvey/convey reflect testing func Test_GetHostInfoHandler(t *testing.T) { reqData : Person{ Name: baijiwei , Age:30, reqBody, _ : json.Marshal(reqData) rw : httptest.NewRecorder() req, err : http.NewRequest( POST , /get_host_info , bytes.NewReader(reqBody)) if err ! nil { t.Fatal(err) GetHostInfoHandler(rw, req) response : Person{} err json.Unmarshal(rw.Body.Bytes(), response) if err ! nil { fmt.Println( unmarshal body fail )}
本文链接: http://monkeymeth.immuno-online.com/view-739941.html