Go: Контрактный тест обработчика и клиента питания — задача с проверкой
Практическая задача на Go по теме «Контрактный тест обработчика и клиента». Условие содержит контракт функций, предоставленные типы и требования к результату. Используйте выданный шаблон и сохраняйте его публичные объявления. Перед проверкой разберите успешный путь, обработку ошибок и отмену операции, когда она предусмотрена контрактом. Здесь оценивается конкретный компонент сервиса; в полном курсе микросервисов на Go эти компоненты связываются с HTTP, PostgreSQL, gRPC и Kafka.
Контрактный тест обработчика и клиента питания
Реализуйте тело функции VerifyNutritionContract(handler http.Handler, call CalculateFunc) error, которая проверяет, что переданные handler и call соблюдают единый HTTP-контракт сервиса расчёта калорий.
Объявления типов, которые уже даны:
type IngredientInput struct {
IngredientID *string `json:"ingredient_id"`
Grams *float64 `json:"grams"`
}
type CalculationRequest struct { Ingredients []IngredientInput `json:"ingredients"` }
type CalculationResponse struct { Calories float64 `json:"calories"` }
type CalculateFunc func(context.Context, *http.Client, string, CalculationRequest) (CalculationResponse, error)
type transportFunc func(*http.Request) (*http.Response, error)
func (f transportFunc) RoundTrip(r *http.Request) (*http.Response, error)
Каркас готовит состав из двух ингредиентов — oats 50 г и banana 100 г — и выполняет все HTTP-вызовы и cleanup за вас. Ваша задача — заполнить условия проверок в предоставленных блоках TODO, не добавляя новых функций, серверов или клиентов.
Что должна проверять функция:
-
Успешный ответ handler. Вызов
POST /calculationsдолжен вернуть статус 200 иContent-Type: application/json(charset допустим). Тело — ровно один JSON-объект с числовым полемcaloriesравным -
Любое переименование поля, нулевое значение вместо числа, лишний текст после объекта или отсутствие поля — нарушение контракта.
-
Ответ handler на неверный запрос. Запрос без поля
gramsобязан вернуть статус 400,Content-Type: application/json, и тело должно содержать только полеerrorсо значением"invalid_request"— без поляcalories. -
Корректность исходящего запроса клиента. Когда
callобращается к fake-серверу, он обязан использовать методPOST, путь/calculationsи заголовокContent-Type: application/json. Декодированное тело запроса должно содержать оба ингредиента с правильными ID и граммами. -
Разбор ответов fake-сервера клиентом. Четыре варианта fake-ответа проверяются отдельно:
{"calories":280}→ успех, значение 280;{"calories":280,"units":"kcal"}→ успех, значение 280 (лишнее поле допустимо);{"calories":73.5}→ успех, значение 73.5;{}→ ошибка (полеcaloriesобязательно, ноль не засчитывается).
-
Отмена контекста. Если контекст уже отменён до вызова
call, функция должна вернуть ошибку, удовлетворяющуюerrors.Is(err, context.Canceled), а не просто любую ошибку.
Дополните TODO в редакторе и отправьте весь код, сохранив package main, импорты, предоставленные типы и публичную функцию RunScenario. Не добавляйте свою функцию main: JSON-адаптер запуска платформа добавит сама. Скрытые входы и ожидаемые результаты находятся на стороне проверки.
Подсказки
- Для проверки media type используйте
mime.ParseMediaType— он отделяет тип от параметров вроде charset, поэтому сравнивать достаточно только базовую часть. - Чтобы убедиться, что в теле ровно один JSON-объект без хвоста, декодируйте его через
json.Decoderи после успешногоDecodeвызовитеDecodeповторно — он должен вернутьio.EOF.
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Связанные задачи
- Go: Принять только полный ответ о последней статье — задача с проверкой
- HTTP-клиент поиска на Go: обработка ответа и ошибок — задача
- Go: Декодирование артефакта из JSON — задача с проверкой
- Go: Обязательная и необязательная зависимость при отказе — задача с проверкой
- Go: HTTP-обработчик поиска задания через JobStore — задача с проверкой
- Go: HTTP-обработчик расчёта калорийности состава — задача с проверкой
