Google app engine 如何对Google App Engine Go HTTP处理程序进行单元测试?

Google app engine 如何对Google App Engine Go HTTP处理程序进行单元测试?,google-app-engine,unit-testing,go,Google App Engine,Unit Testing,Go,本地单元测试来自Google App Engine Go SDK的1.8.6版。appengine/aetest包允许我创建一个上下文来进行单元测试 如何将其与net/http/httptest一起使用来测试我的http处理程序?请参阅goroot/src/pkg/appengine/aetest/context.go的顶部(更新的源代码尚未发布在)。乍一看,新的测试应用程序看起来是一个稍微强大/不同的版本,因此您可以执行相同类型的测试,请参阅,以了解如何调用sampleHandler(w ht

本地单元测试来自Google App Engine Go SDK的1.8.6版。
appengine/aetest
包允许我创建一个
上下文来进行单元测试


如何将其与
net/http/httptest
一起使用来测试我的http处理程序?

请参阅goroot/src/pkg/appengine/aetest/context.go的顶部(更新的源代码尚未发布在)。乍一看,新的测试应用程序看起来是一个稍微强大/不同的版本,因此您可以执行相同类型的测试,请参阅,以了解如何调用sampleHandler(w http.ResponseWriter,r*http.Request)的一种方法

或者,您可以将http.Handler的ContextHandler设置为如下所示:

type ContextHandler struct {
    Real func(*appengine.Context, http.ResponseWriter, *http.Request)
}

func (f ContextHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    c := appengine.NewContext(r)
    f.Real(c, w, r)
}

func myNewHandler(c appengine.Context, w http.ResponseWriter, r *http.Request) {
// do something
}
然后可以在init()中执行此操作以支持生产:

http.Handle("/myNewHandler", ContextHandler{myNewHandler})
这使得测试功能变得容易:

func TestMyNewHandler(t *testing.T) {
    c := aetest.NewContext()
    r, _ := http.NewRequest("GET", "/tasks/findOverdueSchedules", nil)
    w := httptest.NewRecorder()
    myNewHandler(c, w, r)
    if 200 != w.Code {
        t.Fail()
    }
}
以下是来自上下文的内容。进入appengine/aetest内部:

/* 包aetest提供了一个appengine.Context供测试使用

一个示例测试文件: 包foo_测试

环境变量APPENGINE\u API\u SERVER指定 要使用的api_server.py可执行文件。如果未设置,则参考系统路径。 */


如果您不反对使用依赖项注入,那么依赖项注入是解决问题的好方法。以下是设置测试的方法(使用):

在生产过程中,将注入实际上下文:

m.Use(func(c martini.Context, req *http.Request) {
    c.MapTo(appengine.NewContext(req), (*appengine.Context)(nil))
})

在所有非测试代码处理程序中使用
var contextCreator func(r*http.Request)appengine.Context=appengine.NewContext
()似乎不太优雅。在每个http.Handler中使用c:=appengine.NewContext(r)似乎也不太优雅。我已经更新了我的帖子,包括我是如何做到这一点的。我同意你的看法,这似乎是一个很好的解决方案。事实上,我正在使用Gorilla工具包,并对您的示例进行了一些抽象,以供使用,这使我能够添加与设置请求相关的所有其他内容。
var _ = Describe("Items", func() {

    var (
        m *martini.ClassicMartini
    )

    BeforeEach(func() {
        m = martini.Classic()

        // injects app engine context into requests
        m.Use(func(c martini.Context, req *http.Request) {
             con, _ := aetest.NewContext(nil)
             c.MapTo(con, (*appengine.Context)(nil))
        })

        m.Get("/items", func(c martini.Context){
             // code you want to test
        })
    })

    It("should get items", func() {
        recorder := httptest.NewRecorder()
        r, _ := http.NewRequest("GET", "/items", nil)
        m.ServeHTTP(recorder, r) // martini server used
        Expect(recorder.Code).To(Equal(200))
    })
})
m.Use(func(c martini.Context, req *http.Request) {
    c.MapTo(appengine.NewContext(req), (*appengine.Context)(nil))
})