dongtu9823 2018-06-21 09:17 采纳率: 0%
浏览 190
已采纳

使用自定义ServeHTTP实现的HTTP处理程序的golang单元测试

I am trying to write unit test for my http file server. I have implemented the ServeHTTP function so that it'd replace "//" with "/" in the URL:

type slashFix struct {
    mux http.Handler
}

func (h *slashFix) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    r.URL.Path = strings.Replace(r.URL.Path, "//", "/", -1)
    h.mux.ServeHTTP(w, r)
}

The bare-minimum code would look like this:

func StartFileServer() {
    httpMux := http.NewServeMux()
    httpMux.HandleFunc("/abc/", basicAuth(handle))
    http.ListenAndServe(":8000", &slashFix{httpMux})
}

func handle(writer http.ResponseWriter, r *http.Request) {
    dirName := "C:\\Users\\gayr\\GolandProjects\\src\\NDAC\\download\\"    
    http.StripPrefix("/abc",
        http.FileServer(http.Dir(dirName))).ServeHTTP(writer, r)
}

func basicAuth(handler http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        user, pass, ok := r.BasicAuth()
        if user != "UserName" || pass != "Password" {
            w.WriteHeader(401)
            w.Write([]byte("Unauthorised.
"))
            return
        }
        handler(w, r)
    }
}

I came across instances like the following to test http handlers:

req, err := http.NewRequest("GET", "/abc/testfile.txt", nil)
if err != nil {
    t.Fatal(err)
}
req.SetBasicAuth("UserName", "Password")
rr := httptest.NewRecorder()
handler := http.HandlerFunc(basicAuth(handle))
handler.ServeHTTP(rr, req)

Doing so would invoke the ServeHTTP function implemented using http.HandleFunc, but I want ServeHTTP implemented in my code to be invoked. How can this be achieved? Also, is there a way for me to directly test StartFileServer()?

Edit: I checked the link provided in the comments; my question does not appear to be a duplicate. I have a specific question: instead of invoking the ServeHTTP function implemented using http.HandleFunc, I want ServeHTTP implemented in my code to be invoked. I do not see this addressed in the provided link.

  • 写回答

1条回答 默认 最新

  • dongmou3615 2018-06-21 10:37
    关注

    http.HandlerFunc implements http.Handler. As Flimzy pointed out in the comments, there is no need for basicAuth to require a HandlerFunc; any http.Handler will do. Sticking to the http.Handler interface instead of the concrete HandlerFunc type will make everything easily composable:

    func basicAuth(handler http.Handler) http.Handler { // Note: http.Handler, not http.HandlerFunc
            return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
                    user, pass, ok := r.BasicAuth()
                    if !ok {
                            // TODO
                    }
                    if user != "UserName" || pass != "Password" {
                            w.WriteHeader(401)
                            w.Write([]byte("Unauthorised.
    "))
                            return
                    }
    
                    handler.ServeHTTP(w, r)
            })
    }
    
    func TestFoo(t *testing.T) {
            req, err := http.NewRequest("GET", "/abc/testfile.txt", nil)
            if err != nil {
                    t.Fatal(err)
            }
            req.SetBasicAuth("UserName", "Password")
            rr := httptest.NewRecorder()
    
            // composition is trivial now
            sf := &slashFix{
                    mux: http.HandlerFunc(handle),
            }
            handler := basicAuth(sf)
            handler.ServeHTTP(rr, req)
    
            // assert correct rr
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 多台相同IP产品如何组网
  • ¥30 关于php页面调取、更新数据提交刷新等问题
  • ¥50 使用 java+selenium 接管手动打开的IE浏览器
  • ¥15 ios 新安装app收不到fcm推送
  • ¥15 有没有实力的写手?有过成品的优先
  • ¥15 图像信息库的建立与识别
  • ¥15 韩国网站购物,KG支付的支付回调如何解决
  • ¥15 workstation导入ovf文件,报错,怎么解决呢?
  • ¥15 关于#c语言#的问题:构成555单稳态触发器,采用LED指示灯延时时间,对延时时间进行测量并显示(如楼道声控延时灯)需要Proteus仿真图和C语言代码
  • ¥15 workstation加载centos进入emergency模式,查看日志报警如图,怎样解决呢?