【问题标题】:How to mock an http.Handler with Go's moq?如何使用 Go 的 moq 模拟 http.Handler?
【发布时间】:2020-05-04 21:11:51
【问题描述】:

我有兴趣创建一个httptest.Server,它只记录调用它的请求。为此,我想使用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)
}

我该如何解决这个问题以使用模拟处理程序函数制作测试服务器?

【问题讨论】:

  • httptestServerResponseRecorder 是执行此操作的惯用方式。无需第三方模拟库。

标签: unit-testing go interface mocking go-interface


【解决方案1】:

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

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

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

【讨论】:

    猜你喜欢
    • 2012-03-18
    • 2010-10-19
    • 2016-09-30
    • 2019-10-06
    • 1970-01-01
    • 2020-10-27
    • 2012-06-01
    • 2018-12-27
    • 2019-06-16
    相关资源
    最近更新 更多