新建一个项目后,会自动生成一个default_test.go的测试文件,下面看一下它的运行流程。
package test
import (
"net/http"
"net/http/httptest"
"testing"
"runtime"
"path/filepath"
_ "myproject/routers"
"github.com/astaxie/beego"
. "github.com/smartystreets/goconvey/convey"
)
func init() {
_, file, _, _ := runtime.Caller(0)
//fmt.Println(" file:",file)
apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".." + string(filepath.Separator))))
//fmt.Println("apppath:",apppath)
beego.TestBeegoInit(apppath)
}
// TestBeego is a sample to run an endpoint test
func TestBeego(t *testing.T) {
r, _ := http.NewRequest("GET", "/", nil)
w := httptest.NewRecorder()
beego.BeeApp.Handlers.ServeHTTP(w, r)
beego.Trace("testing", "TestBeego", "Code[%d]\n%s", w.Code, w.Body.String())
Convey("Subject: Test Station Endpoint\n", t, func() {
Convey("Status Code Should Be 200", func() {
So(w.Code, ShouldEqual, 200)
})
Convey("The Result Should Not Be Empty", func() {
So(w.Body.Len(), ShouldBeGreaterThan, 0)
})
})
}
func init() {
_, file, _, _ := runtime.Caller(0)
//fmt.Println(" file:",file)
apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".." + string(filepath.Separator))))
//fmt.Println("apppath:",apppath)
beego.TestBeegoInit(apppath)
}
首先 _, file, _, _ := runtime.Caller(0) 模板为:
func Caller(skip int) (pc uintptr, file string, line int, ok bool)
参数:skip是要提升的堆栈帧数,0-当前函数,1-上一层函数,…
返回值:
pc是uintptr这个返回的是函数指针
file是函数所在文件名目录
line所在行号
ok 是否可以获取到信息
通过加打印可获得file的值
root@ZTE:/usr/lib/go/src/myproject/tests# go test -v
file: /usr/lib/go/src/myproject/tests/default_test.go
其次,apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, “…” + string(filepath.Separator))))中 filepath.Join(file, “…” + string(filepath.Separator))可获得上一层目录
/usr/lib/go/src/myproject/tests
filepath.Dir() 会去掉最后的文件元素,获得
/usr/lib/go/src/myproject
filepath.Abs()获得绝对路径,通过打印可得到:
root@ZTE:/usr/lib/go/src/myproject/tests# go test
apppath: /usr/lib/go/src/myproject
最后,执行beego.TestBeegoInit(apppath),即beego.TestBeegoInit(“/usr/lib/go/src/myproject”)进行test的初始化。
// TestBeegoInit is for test package init
func TestBeegoInit(ap string) {
path := filepath.Join(ap, "conf", "app.conf")
os.Chdir(ap)
InitBeegoBeforeTest(path)
}
// InitBeegoBeforeTest is for test package init
func InitBeegoBeforeTest(appConfigPath string) {
if err := LoadAppConfig(appConfigProvider, appConfigPath); err != nil {
panic(err)
}
BConfig.RunMode = "test"
initBeforeHTTPRun()
}
InitBeegoBeforeTest(path)即InitBeegoBeforeTest((“/usr/lib/go/src/myproject/conf/app.conf”)
在 InitBeegoBeforeTest()主要是加载配置文件,修改运行模式为test,最后做启动程序前的初始化。
func initBeforeHTTPRun() {
//init hooks
AddAPPStartHook(
registerMime,
registerDefaultErrorHandler,
registerSession,
registerTemplate,
registerAdmin,
registerGzip,
)
for _, hk := range hooks {
if err := hk(); err != nil {
panic(err)
}
}
}
func TestBeego(t *testing.T) {
r, _ := http.NewRequest("GET", "/", nil)
w := httptest.NewRecorder()
beego.BeeApp.Handlers.ServeHTTP(w, r)
beego.Trace("testing", "TestBeego", "Code[%d]\n%s", w.Code, w.Body.String())
Convey("Subject: Test Station Endpoint\n", t, func() {
Convey("Status Code Should Be 200", func() {
So(w.Code, ShouldEqual, 200)
})
Convey("The Result Should Not Be Empty", func() {
So(w.Body.Len(), ShouldBeGreaterThan, 0)
})
})
}
在TestBeego测试方法下,需要携带*testing.T参数(T是传递给“测试”功能的一种类型,用于管理测试状态并支持格式化的测试日志)
type T struct {
common
isParallel bool
context *testContext // For running tests and subtests.
}
函数内需构建发Request,NewRecorder返回ResponseRecorder,实现了ResponseWriter。最后beego.BeeApp.Handlers.ServeHTTP(w, r)为ControllerRegister处理器来处理HTTP Server。
// Trace logs a message at trace level.
func Trace(v ...interface{}) {
logs.Trace(generateFmtStr(len(v)), v...)
}
Convey()是一个顶层的测试块,参数有描述,testing.T,方法。func()内嵌套的Convey()为具体测试用例,参数包括测试描述和测试函数,而So()相当于断言的作用。