Проверить код состояния с помощью 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 блок исполняется.

Другие вопросы по тегам