如何用 Go 的最小起订量模拟 http.Handler?

How to mock an http.Handler with Go's moq?

我有兴趣创建一个 httptest.Server which simply records the requests it is called with. To this end, I'd like to use the github.com/matryer/moq 库。

为了为 http.Handler 生成模拟,我将其定义复制到名为 client:

的包中
package client

import "net/http"

type Handler interface {
    ServeHTTP(http.ResponseWriter, *http.Request)
}

我然后运行

moq -out handler_mock.go . Handler

client 目录中,生成以下内容 handler_mock.go:

// Code generated by moq; DO NOT EDIT.
// github.com/matryer/moq

package client

import (
    "net/http"
    "sync"
)

var (
    lockHandlerMockServeHTTP sync.RWMutex
)

// Ensure, that HandlerMock does implement Handler.
// If this is not the case, regenerate this file with moq.
var _ Handler = &HandlerMock{}

// HandlerMock is a mock implementation of Handler.
//
//     func TestSomethingThatUsesHandler(t *testing.T) {
//
//         // make and configure a mocked Handler
//         mockedHandler := &HandlerMock{
//             ServeHTTPFunc: func(in1 http.ResponseWriter, in2 *http.Request)  {
//                 panic("mock out the ServeHTTP method")
//             },
//         }
//
//         // use mockedHandler in code that requires Handler
//         // and then make assertions.
//
//     }
type HandlerMock struct {
    // ServeHTTPFunc mocks the ServeHTTP method.
    ServeHTTPFunc func(in1 http.ResponseWriter, in2 *http.Request)

    // calls tracks calls to the methods.
    calls struct {
        // ServeHTTP holds details about calls to the ServeHTTP method.
        ServeHTTP []struct {
            // In1 is the in1 argument value.
            In1 http.ResponseWriter
            // In2 is the in2 argument value.
            In2 *http.Request
        }
    }
}

// ServeHTTP calls ServeHTTPFunc.
func (mock *HandlerMock) ServeHTTP(in1 http.ResponseWriter, in2 *http.Request) {
    if mock.ServeHTTPFunc == nil {
        panic("HandlerMock.ServeHTTPFunc: method is nil but Handler.ServeHTTP was just called")
    }
    callInfo := struct {
        In1 http.ResponseWriter
        In2 *http.Request
    }{
        In1: in1,
        In2: in2,
    }
    lockHandlerMockServeHTTP.Lock()
    mock.calls.ServeHTTP = append(mock.calls.ServeHTTP, callInfo)
    lockHandlerMockServeHTTP.Unlock()
    mock.ServeHTTPFunc(in1, in2)
}

// ServeHTTPCalls gets all the calls that were made to ServeHTTP.
// Check the length with:
//     len(mockedHandler.ServeHTTPCalls())
func (mock *HandlerMock) ServeHTTPCalls() []struct {
    In1 http.ResponseWriter
    In2 *http.Request
} {
    var calls []struct {
        In1 http.ResponseWriter
        In2 *http.Request
    }
    lockHandlerMockServeHTTP.RLock()
    calls = mock.calls.ServeHTTP
    lockHandlerMockServeHTTP.RUnlock()
    return calls
}

但是,如果我尝试 运行 以下 client_test.go

package client

import (
    "net/http"
    "net/http/httptest"
    "testing"
)

func TestHandlerMock(t *testing.T) {
    handlerMock := HandlerMock{
        ServeHTTPFunc: func(w http.ResponseWriter, r *http.Request) {},
    }

    ts := httptest.NewServer(handlerMock)
    defer ts.Close()
}

我明白了

# github.com/kurtpeek/mock-handler/client [github.com/kurtpeek/mock-handler/client.test]
/Users/kurt/go/src/github.com/kurtpeek/mock-handler/client/client_test.go:14:26: cannot use handlerMock (type HandlerMock) as type http.Handler in argument to httptest.NewServer:
    HandlerMock does not implement http.Handler (ServeHTTP method has pointer receiver)
FAIL    github.com/kurtpeek/mock-handler/client [build failed]
Error: Tests failed.

确实,如果我查看 ServeHTTP 的实际定义(来自 https://github.com/golang/go/blob/c112289ee4141ebc31db50328c355b01278b987b/src/net/http/server.go#L2008-L2013),ServeHTTP() 没有指针接收器:

// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)

// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}

我该如何解决这个问题来制作一个带有模拟处理函数的测试服务器?

错误消息说您的 HandlerMock 没有实现接口 http.Handler。但是,*HandlerMock 确实实现了它:

func (mock *HandlerMock) ServeHTTP(in1 http.ResponseWriter, in2 *http.Request) 

尝试将语句 ts := httptest.NewServer(handlerMock) 更改为 ts := httptest.NewServer(&handlerMock)