TLDR: существует промежуточное ПО go-chi
, которое выполняет внешний вызов для авторизации запроса. Мне нужно издеваться над тем, что он делает.
Подробности:
У меня есть этот тест:
func Test_HTTP_UserSet_Create_InvalidAction(t *testing.T) {
requestBody :=
`{
"name": "test",
"action": "TEST"
}`
req, _ := http.NewRequest("POST", "/1234/users", bytes.NewBuffer([]byte(requestBody)))
recorder := setupInvalidActionRecorder(t, req)
if status := recorder.Code; status != http.StatusBadRequest {
t.Errorf("Status code expected to be %d but got %d", http.StatusBadRequest, status)
return
}
}
Вышеупомянутое setupUnknownErrorRecorder
:
func setupUnknownErrorRecorder(t *testing.T, request *http.Request) *httptest.ResponseRecorder {
recorder := httptest.NewRecorder()
c := resty.New()
resource := users.NewResource(
httpClient.NewHttpClient(log, &config.Server{}, &logger.LogRecord{}, c),
)
resource.Routes().ServeHTTP(recorder, request)
return recorder
}
Результат, который я получаю:
=== RUN Test_HTTP_UserSet_Create_InvalidAction
invalidAction_test.go:71: Status code expected to be 400 but got 401
--- FAIL: Test_HTTP_UserSet_Create_InvalidAction (0.00s)
Этот результат ожидается, так как сервер выполняет внешний вызов, используя клиент c
, который я передаю NewResource
.
Существует промежуточное ПО go-chi
, которое использует этот клиент для выполнения внешнего вызова.
Мой вопрос: как я могу заставить этот http-вызов всегда возвращать 200 без действительного вызова. Ака как издеваться над этим звонком?
Редактировать: Интерфейс httpClient выше:
type HttpClient struct {
logger *logger.Logger
config *config.Server
instrumentation *instrumentation
record *logger.LogRecord
restyClient *resty.Client
}
func NewHttpClient(
logger *logger.Logger,
config *config.Server,
record *logger.LogRecord,
restyClient *resty.Client,
) HttpClient {
return HttpClient{
instrumentation: newInstrumentation(logger, record),
config: config,
logger: logger,
record: record,
restyClient: restyClient,
}
}
Очень простое правило тестируемого кода гласит, что вы не можете просто создавать новые сервисы внутри других ваших сервисов. Вам нужно внедрить его и подготовить интерфейс, если его еще нет, для того, что возвращается resty.New
. Таким образом, вы можете ввести свой макет в тесты.
Затем вы можете использовать, например, https://pkg.go.dev/github.com/stretchr/testify/mock для создания макетов и указания того, каким должно быть возвращаемое значение вашей имитируемой службой.
Обновление после комментария:
type HttpClient struct {
logger *logger.Logger
config *config.Server
instrumentation *instrumentation
record *logger.LogRecord
restyClient *resty.Client // <- this is the thing you want to change from a pointer to resty.Client to an interface
}
Проверьте, какие методы restyClient
вы используете в коде, и создайте новый интерфейс, содержащий их, например:
type MyRestyClient interface {
FirstUsedMethod(..)
...
}
и замените объявление restyClient на
type HttpClient struct {
...
restyClient MyRestyClient
после этого вы можете использовать насмешку по ссылке, которую я вставил ранее, с командой, чтобы сгенерировать для вас насмешку.
Позже вы просто настраиваете макет в тестах:
restyMock := new(RestyMock)
restyMock.On("MethodYouExpect").Return(returnValueOfYourChoice)
и вы вводите подготовленный mock в свой тестируемый сервис.
Отредактировал мой ответ, так как он дает больше контекста вопросу.
Благодарю вас! Но, пожалуйста, потерпите меня. В какой момент можно использовать настоящий клиент Resty resty.New()
? Я сделал то, что вы объяснили, но когда я использую это в простом httpClientInst := httpClient.NewHttpClient(log, &config, rec, resty.New())
, я получаю обычную ошибку типа cannot use resty.New() (value of type *resty.Client) as *httpClient.MyRestyClientInterface value in argument to httpClient.NewHttpClient
. В конце концов, весь смысл в использовании метода настоящей библиотеки.
Что ж, если вы хотите протестировать другой сервис, вам следует смоделировать все зависимости. Вероятно, клиент, который вы используете, уже был протестирован, так зачем еще раз его тестировать? Вместо этого просто используйте макет для своих тестов, чтобы проверить свой HttpClient.
Верно. Я близок к полному пониманию этого. Большое спасибо!
Спасибо за ответ! У меня есть интерфейс для службы. Я добавил код интерфейса к вопросу. Вы можете видеть, где находится
*resty.Client
. Но я не знаю, как создать новый экземпляр службы с издевательским*resty.Client
в нем. Можете ли вы провести здесь?