Проверить код состояния с помощью ExUnit не удалось, но фактический тест REST успешно
Я пишу функцию контроллера, где он будет проверять условие (ключевое слово, чтобы быть действительным), прежде чем либо визуализировать объект json, либо объект ошибки в случае неудачи.
router.ex
scope "/api", DongNghiaWeb do
pipe_through :api
scope "/tim_kiem" do
get "/tu/:word" , APIWordController, :search_word
[...]
word_controller.ex
def search_word(conn, %{"word" => word}) do
conn
|> check_invalid_keyword(word)
|> render("search.json", words: word |> String.trim |> Words.suggest)
end
defp check_invalid_keyword(conn, keyword) do
unless Words.keyword_valid?(String.trim(keyword)) do
conn
|> put_status(400)
|> json(%{
error: "Invalid keyword"
})
end
conn
end
word_controller_test.ex
test "response error when word is not valid", %{conn: conn} do
response = get(conn,api_word_path(conn, :search_word, "a3d"))
|> json_response(400)
assert response["error"] == "Invalid keyword"
end
При беге mix test
, результаты будут выглядеть так:
** (RuntimeError) expected response with status 400, got: 200, with body: {"data":[]}
Но когда я пытаюсь протестировать с клиентом REST (например, с бессонницей), json вернется к { error : "Invalid keyword" }
просто хорошо.
1 ответ
Ваш код пишет ответ на соединение дважды, когда Words.keyword_valid?(String.trim(keyword))
это ложь
Первая запись происходит, когда вы звоните |> json(...)
и второй, когда вы звоните render
, Ваш код не мешает render
вызывается когда json
уже был вызван. Соединение с браузером завершается после первой записи, поэтому вы видите правильный вывод с Insomnia, но в настройках тестирования используется последний ответ, записанный для соединения.
Исправление требует небольшой реструктуризации вашего кода. Вот как бы я это сделал:
def search_word(conn, %{"word" => word}) do
if Words.keyword_valid?(String.trim(word)) do
conn
|> render("search.json", words: word |> String.trim() |> Words.suggest())
else
conn
|> put_status(400)
|> json(%{
error: "Invalid keyword"
})
end
end
Изменить: вот один из способов сделать то, что вы просили в комментарии ниже:
def search_word(conn, %{"word" => word}) do
with {:ok, conn} <- check_invalid_keyword(conn, word) do
conn
|> render("search.json", words: word |> String.trim() |> Words.suggest())
end
end
def check_invalid_keyword(conn, keyword) do
if Words.keyword_valid?(String.trim(keyword)) do
{:ok, conn}
else
conn
|> put_status(400)
|> json(%{
error: "Invalid keyword"
})
end
end
Когда ключевое слово недопустимо, возвращаемое значение не соответствует with
пункт и возвращается как есть. Если это было действительно, то do
блок исполняется.