Мокинг интерфейса, определенного в тестовом файле: interface "Undefined"?
Это ошибка, которую я пытался воспроизвести на минимальном примере, но пока безуспешно. Модуль Go похож на следующий:
.
├── go.mod
└── handler
├── handler.go
├── handler_test.go
└── mock_handler.go
где handler.go
пусто (содержит package handler
только), handler_test.go
содержит Handler
определение интерфейса (такое же, как у Go http.Handler
) и тест-заполнитель,
package handler
import (
"net/http"
"testing"
)
type Handler interface {
ServeHTTP(http.ResponseWriter, *http.Request)
}
func TestMockHandler(t *testing.T) {
mockHandler := MockHandler{}
t.Log(mockHandler)
}
а также mock_handler.go
содержит MockHandler
структура, которая реализует Handler
интерфейс и создается с использованием moq
:
// Code generated by moq; DO NOT EDIT.
// github.com/matryer/moq
package handler
import (
"net/http"
"sync"
)
var (
lockMockHandlerServeHTTP sync.RWMutex
)
// Ensure, that MockHandler does implement Handler.
// If this is not the case, regenerate this file with moq.
var _ Handler = &MockHandler{}
// MockHandler is a mock implementation of Handler.
//
// func TestSomethingThatUsesHandler(t *testing.T) {
//
// // make and configure a mocked Handler
// mockedHandler := &MockHandler{
// 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 MockHandler 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 *MockHandler) ServeHTTP(in1 http.ResponseWriter, in2 *http.Request) {
if mock.ServeHTTPFunc == nil {
panic("MockHandler.ServeHTTPFunc: method is nil but Handler.ServeHTTP was just called")
}
callInfo := struct {
In1 http.ResponseWriter
In2 *http.Request
}{
In1: in1,
In2: in2,
}
lockMockHandlerServeHTTP.Lock()
mock.calls.ServeHTTP = append(mock.calls.ServeHTTP, callInfo)
lockMockHandlerServeHTTP.Unlock()
mock.ServeHTTPFunc(in1, in2)
}
// ServeHTTPCalls gets all the calls that were made to ServeHTTP.
// Check the length with:
// len(mockedHandler.ServeHTTPCalls())
func (mock *MockHandler) ServeHTTPCalls() []struct {
In1 http.ResponseWriter
In2 *http.Request
} {
var calls []struct {
In1 http.ResponseWriter
In2 *http.Request
}
lockMockHandlerServeHTTP.RLock()
calls = mock.calls.ServeHTTP
lockMockHandlerServeHTTP.RUnlock()
return calls
}
Чтобы создать mock_handler.go
, Я изначально определил Handler
в handler.go
а затем в handler
каталог, выполнил команду
moq -out mock_handler.go . Handler
Впоследствии я переместил Handler
определение интерфейса для handler_test.go
поскольку он предназначен только для использования в тестах.
В этом упрощенном примере я могу запустить go test
в режиме списка пакетов в корневом каталоге:
~/g/s/g/k/mockhandler> go test ./... -count=1
ok github.com/kurtpeek/mockhandler/handler 0.448s
Мой "фактический" модуль имеет аналогичную структуру, подобную следующей:
.
├── cmd
│ └── root.go
├── images
├── main.go
└── vpp
├── ensure_license_test.go
└── mock_handler.go
В Handler
интерфейс определяется точно так же в ensure_license_test.go
как в handler_test.go
в упрощенном модуле; ensure_license_test.go
начинается так:
package vpp
import (
"encoding/json"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type Handler interface {
ServeHTTP(http.ResponseWriter, *http.Request)
}
type MockTestServer struct {
TestServer *httptest.Server
MockHandler *MockHandler
}
mock_handler.go
также точно такой же, как mock_handler.go
в упрощенном модуле (кроме названия пакета).
Но когда я бегу go test ./...
в корневом каталоге "фактического" модуля я получаю undefined
ошибка для Handler
:
~/g/s/g/f/vpp-client> go test ./... -count=1
# github.com/fleetsmith/vpp-client/vpp
vpp/mock_handler.go:17:7: undefined: Handler
ok github.com/fleetsmith/vpp-client/vpp 0.128s
Как ни странно, когда я запускаю это изнутри vpp
пакет, он проходит:
> go test ./... -count=1
ok github.com/fleetsmith/vpp-client/vpp 0.601s
Что могло быть причиной того, что go test
не может дать определение Handler
при запуске в режиме списка пакетов из корневого каталога, как в первом примере?
1 ответ
Оказывается, это был cmd
пакет, тесты которого завершились неудачно, потому что не удалось импортировать Handler
интерфейс из тестового файла в vpp
пакет. Итак, я изменил строку 17 изmock_handler.go
использовать http.Handler
а не Handler
:
var _ http.Handler = &MockHandler{}
Теперь тесты проходят:
~/g/s/g/f/vpp-client> go test ./...
? github.com/fleetsmith/vpp-client [no test files]
? github.com/fleetsmith/vpp-client/cmd [no test files]
ok github.com/fleetsmith/vpp-client/vpp 0.462s
Я также смог удалить определение Handler
интерфейс от ensure_license_test.go
так как теперь я использую определение из http
стандартная библиотека напрямую.
Недостатком этого подхода является то, что он требует редактирования кода, который был автоматически сгенерирован moq
однако я не мог понять, как запустить moq
имитировать интерфейсы в стандартной библиотеке Go, и в любом случае этот интерфейс вряд ли изменится.