在 Phoenix 应用程序中为异常设置自定义响应

Setting up custom response for exception in Phoenix Application

我正在使用 ecto 编写 phoenix 应用程序并在测试中包含以下代码片段

{:ok, data} = Poison.encode(%{email: "nonexisting@user.com", password: "mypass"})

conn()
|> put_req_header("content-type", "application/json")
|> put_req_header("accept", "application/json")
|> post(session_path(@endpoint, :create), data)
> json_response(:not_found) == %{}

这会抛出一个 Ecto.NoResultsError

我已经定义了这个

defimpl Plug.Exception, for: Ecto.NoResultsError do
  def status(_exception), do: 404
end

但测试仍然抛出 Ecto.NoResultsError,有任何指示吗?

让我们考虑一下它在每个环境中的工作方式。

  • :prod中,默认是渲染错误页面,所以你应该看到一个由YourApp.ErrorView渲染的页面,带有状态码;

  • :dev 中,默认显示调试页面,因为大多数情况下您在构建代码时都会出错。如果你想看到实际呈现的错误页面,你需要在你的 config/dev.exs;

  • 中设置 debug_errors: false
  • :test 中,它像生产一样工作,但是,因为您是从测试中调用您的应用程序,所以如果您的应用程序崩溃,您的测试也会崩溃。我们在未来的版本中对此进行了改进,您应该可以在其中编写如下内容:

    assert_raise Ecto.NoResultsError, fn ->
      get conn, "/foo"
    end
    {status, headers, body} = sent_response(conn)
    assert status == 404
    assert body =~ "oops"
    

Phoenix 1.1.0 引入了Phoenix.ConnTest.assert_error_sent/2以简化类似案例的测试。

来自the documentation

Asserts an error was wrapped and sent with the given status.

Useful for testing actions that you expect raise an error and have the response wrapped in an HTTP status, with content usually rendered by your MyApp.ErrorView.

用法示例:

assert_error_sent :not_found, fn ->
  get conn(), "/users/not-found"
end

response = assert_error_sent 404, fn ->
  get conn(), "/users/not-found"
end
assert {404, [_h | _t], "Page not found"} = response