golang 模拟依赖项中的单元测试 http 处理程序

Sub*_*bby 2 unit-testing dependency-injection go

目前,我尝试为单元测试 go 处理程序建立最佳实践。我需要模拟依赖项,但因此我必须能够访问/模拟这些依赖项。

我不想考虑一些解决方案,例如全局变量/应用程序状态。或者将所有处理程序作为包含依赖项成员变量的结构的函数。

我对通过以下方式注入处理程序所需的依赖项的解决方案感到满意:

func helloHandler(db *DbService) http.HandlerFunc {
  return func(w http.ResponseWriter, r *httpRequest) {
    // handler code goes here
  }
}
Run Code Online (Sandbox Code Playgroud)

然后我可以为路由提供这个处理程序:

http.HandleFunc("/hello", helloHander(myDbService))
Run Code Online (Sandbox Code Playgroud)

我也可以轻松测试:

helloHandler(myDbService)(req, respRecorder)
Run Code Online (Sandbox Code Playgroud)

但是当我使用例如大猩猩复用器(我从一开始就没有考虑过)时,我又遇到了另一个问题。

Gorilla/mux 添加了额外的语义,如按方法过滤(GET / POST)、提供路径参数等。

所以我需要测试生成的大猩猩路由器。但是后来我再次无法注入我的模拟依赖项。

当我取回路由器时,一切(依赖项)都已经设置好了。

但是我也不想因为 DRY 在我的测试中重建我的路由器!

所以现在我真的没有一个很好的解决方案来方便地设置我的路线,但也能够模拟依赖项。

任何的想法?

ale*_*xbt 5

我个人将我的路由器功能更改为带有接收器的方法,因此我可以创建 Mock 接收器:

生产代码:

func main(){
    router := mux.NewRouter()
    version.AddRouter(router, contextRoot)
    someStruct := SomeStruct{SomeDependency{}}
    router.HandleFunc(contextRoot, someStruct.HandleRequests).
           Methods(http.MethodGet)
}

func (s SomeStruct) HandleRequests(writer http.ResponseWriter, reader *http.Request) {
    ...
}

func (s SomeDependency) SomeFunctionCalledFromHandler(...) SomeReturnStruct {
    ...
    return SomeReturnStruct{}
}
Run Code Online (Sandbox Code Playgroud)

单元测试:

type mockWriter struct {}
type someMockDependency struct {}
func Test_HandleRequest1(t *testing.T) {

    someStructMockDeps := SomeStruct{someMockDependency{}}
    someStructMockDeps.HandleRequests(mockWriter{}, &http.Request{URL: &url.URL{RawQuery:"http://dummy-query.com"}});

    assert.Equal(...)
}
func (someMockDependency) SomeFunctionCalledFromHandler(...) SomeReturnStruct {
    ...
    return SomeReturnStruct{}
}
Run Code Online (Sandbox Code Playgroud)

集成测试:

func TestHandlerFuncIntg(t *testing.T) {
    if testing.Short() {
        println("skipping")
        t.Skip()
     }

    req, err := http.NewRequest("GET", "/hello?param=value", nil)
    if err != nil {
        t.Fatal(err)
    }

    rr := httptest.NewRecorder()
    someStructMockDeps := SomeStruct{someMockDependency{}}
    handler :=   http.HandlerFunc(someStructMockDeps.HandleRequests)

    handler.ServeHTTP(rr, req)

    assert.Equal(t, http.StatusOK, rr.Code)
    assert.Equal(t, "This is my result", rr.Body.String())
}

func (someMockDependency) SomeFunctionCalledFromHandler(...) SomeReturnStruct {
    ...
    return SomeReturnStruct{}
}
Run Code Online (Sandbox Code Playgroud)

SomeStruct 声明依赖项(作为依赖注入),以便它们可以被覆盖以进行测试。