目前,我尝试建立单元测试的最佳实践。 我需要模拟依赖项,但因此我必须能够访问/模拟这些依赖项。
我有一些我不想考虑的解决方案,例如全局变量/应用程序状态。或者将所有处理程序作为包含依赖项成员变量的结构的函数。
我对解决方案很满意,我以下列方式注入了处理程序所需的依赖项:
func helloHandler(db *DbService) http.HandlerFunc {
return func(w http.ResponseWriter, r *httpRequest) {
// handler code goes here
}
}
然后我能够为路由提供这个处理程序:
http.HandleFunc("/hello", helloHander(myDbService))
我也可以轻松测试一下:
helloHandler(myDbService)(req, respRecorder)
但是当我使用例如大猩猩mux(我从一开始就没有考虑过)时,我又遇到了另一个问题。
Gorilla / mux增加了额外的语义,比如Method(GET / POST)过滤,提供路径参数等。
所以我应该测试生成的大猩猩路由器。 但是我再也无法注入我的模拟依赖项了。
当我收到路由器时,已经设置了所有(依赖项)。
但是我也不想因为DRY而在我的测试中重建我的路由器!
所以现在我没有一个很好的解决方案来解决方便设置路线的问题,但也能够模拟依赖关系。
有什么想法吗?
答案 0 :(得分:2)
我个人将路由器功能改为使用Receiver的方法,因此我可以创建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{}
}
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{}
}
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{}
}
SomeStruct
声明了依赖项(作为依赖注入),因此可以覆盖它们以进行测试。