使用 ConnTest 的 post 发送无效 JSON
Sending invalid JSON with ConnTest's post
我正在尝试测试我的端点是否在无效时返回 400 JSON。如果我这样做:
response = conn
|> put_req_header("content-type", "application/json")
|> post(Routes.convert_path(conn, :convert), "invalid JSON")
我会得到一个 Jason.DecodeError
,因为它正在尝试对我的字符串进行编码。我怎样才能让它不编码呢?查看文档似乎无法完成:
post(conn, path_or_action, params_or_body \ nil)
还有其他方法可以完成我想要完成的事情吗?
test/github_omg_web/controllers/convert_controller_test.exs:36
** (Plug.Parsers.ParseError) malformed request, a Jason.DecodeError exception was raised with message "unexpected byte at position 0: 0x61 ('a')"
code: |> post(Routes.convert_path(conn, :convert), "asdf")
stacktrace:
(plug) lib/plug/parsers/json.ex:97: Plug.Parsers.JSON.decode/2
(plug) lib/plug/parsers.ex:271: Plug.Parsers.reduce/7
(github_omg) lib/github_omg_web/endpoint.ex:1: GithubOmgWeb.Endpoint.plug_builder_call/2
(github_omg) lib/github_omg_web/endpoint.ex:1: GithubOmgWeb.Endpoint.call/2
(phoenix) lib/phoenix/test/conn_test.ex:235: Phoenix.ConnTest.dispatch/5
test/github_omg_web/controllers/convert_controller_test.exs:40: (test)
我创建了一个最小示例以确保我们在同一页面上:
mix phx.new github_omg
mix ecto.create
mix phx.gen.json Accounts User users name:string
mix ecto.migrate
iex -S mix phx.server
要复制,您可以一条一条地粘贴命令,然后按照说明进行操作,例如(phx.gen.json
指示在 lib/github_omg_web/router.ex
中将 resources "/users", UserController, except: [:new, :edit]
添加到 scope "/api"
。
这是创建了一个同名的新项目 github_omg
,一个名为 Accounts
的上下文和一个名为 localhost:4000/api/users
的 api 端点
让我们用 curl
:
执行格式错误的请求
curl --write-out '%{http_code}' --silent -X POST -H "Content-Type: application/json" --data "Invalid JSON" --output /dev/null localhost:4000/api/users
我正在使用 --silent
和 --output /dev/null
来隐藏响应 body。在开发模式下,它将输出整个 Phoenix 错误网页并使输出混乱。 --write-out '%{http_code}
显示 http 状态,-H
添加 headers,--data
是我们发送的无效 JSON。
输出将是:
400
看来 Phoenix 正确输出了 400。
在 Phoenix 控制台中,我们将看到:
[info] POST /api/users
[debug] ** (Plug.Parsers.ParseError) malformed request, a Jason.DecodeError exception was raised with message "unexpected byte at position 0: 0x49 ('I')"
所以看起来 Phoenix 在后台自动将 ParseError
转换为 400。实际上,它并没有那么神奇:)
Phoenix 使用 Plug.Exception
协议计算误差。基本上,您可以抛出任何您喜欢的异常。 defexception
宏允许您在异常中附加自定义字段。 Phoenix 查找名为 plug_status
的字段。 Plug.Parser
定义 ParseError
到 return 400。
回到原来的问题:
你误读了堆栈错误。测试框架不会尝试对有效负载进行编码。这是您的应用程序试图对其进行解码(但失败了)。您可以向后阅读堆栈跟踪:
- 测试调用端点(这已经是您的应用程序代码)
- 端点调用插件解析器
- 此插件抛出异常
这意味着您有两个选择:
- 你完全可以跳过那个测试。它不是您的应用程序逻辑的一部分,测试您正在使用的框架可能没有意义。
- 如果你真的想确定(因为例如,你正在弄乱带有自定义插件的
api
管道),而不是检查 400,你可以检查你的应用程序是否出现正确的错误:
assert_raise Plug.Parsers.ParseError, fn ->
conn
|> put_req_header("content-type", "application/json")
|> post(Routes.convert_path(conn, :convert), "invalid JSON")
end
只有在明确设置 conn 的情况下,您才明确测试 400。
我正在尝试测试我的端点是否在无效时返回 400 JSON。如果我这样做:
response = conn
|> put_req_header("content-type", "application/json")
|> post(Routes.convert_path(conn, :convert), "invalid JSON")
我会得到一个 Jason.DecodeError
,因为它正在尝试对我的字符串进行编码。我怎样才能让它不编码呢?查看文档似乎无法完成:
post(conn, path_or_action, params_or_body \ nil)
还有其他方法可以完成我想要完成的事情吗?
test/github_omg_web/controllers/convert_controller_test.exs:36
** (Plug.Parsers.ParseError) malformed request, a Jason.DecodeError exception was raised with message "unexpected byte at position 0: 0x61 ('a')"
code: |> post(Routes.convert_path(conn, :convert), "asdf")
stacktrace:
(plug) lib/plug/parsers/json.ex:97: Plug.Parsers.JSON.decode/2
(plug) lib/plug/parsers.ex:271: Plug.Parsers.reduce/7
(github_omg) lib/github_omg_web/endpoint.ex:1: GithubOmgWeb.Endpoint.plug_builder_call/2
(github_omg) lib/github_omg_web/endpoint.ex:1: GithubOmgWeb.Endpoint.call/2
(phoenix) lib/phoenix/test/conn_test.ex:235: Phoenix.ConnTest.dispatch/5
test/github_omg_web/controllers/convert_controller_test.exs:40: (test)
我创建了一个最小示例以确保我们在同一页面上:
mix phx.new github_omg
mix ecto.create
mix phx.gen.json Accounts User users name:string
mix ecto.migrate
iex -S mix phx.server
要复制,您可以一条一条地粘贴命令,然后按照说明进行操作,例如(phx.gen.json
指示在 lib/github_omg_web/router.ex
中将 resources "/users", UserController, except: [:new, :edit]
添加到 scope "/api"
。
这是创建了一个同名的新项目 github_omg
,一个名为 Accounts
的上下文和一个名为 localhost:4000/api/users
让我们用 curl
:
curl --write-out '%{http_code}' --silent -X POST -H "Content-Type: application/json" --data "Invalid JSON" --output /dev/null localhost:4000/api/users
我正在使用 --silent
和 --output /dev/null
来隐藏响应 body。在开发模式下,它将输出整个 Phoenix 错误网页并使输出混乱。 --write-out '%{http_code}
显示 http 状态,-H
添加 headers,--data
是我们发送的无效 JSON。
输出将是:
400
看来 Phoenix 正确输出了 400。
在 Phoenix 控制台中,我们将看到:
[info] POST /api/users
[debug] ** (Plug.Parsers.ParseError) malformed request, a Jason.DecodeError exception was raised with message "unexpected byte at position 0: 0x49 ('I')"
所以看起来 Phoenix 在后台自动将 ParseError
转换为 400。实际上,它并没有那么神奇:)
Phoenix 使用 Plug.Exception
协议计算误差。基本上,您可以抛出任何您喜欢的异常。 defexception
宏允许您在异常中附加自定义字段。 Phoenix 查找名为 plug_status
的字段。 Plug.Parser
定义 ParseError
到 return 400。
回到原来的问题:
你误读了堆栈错误。测试框架不会尝试对有效负载进行编码。这是您的应用程序试图对其进行解码(但失败了)。您可以向后阅读堆栈跟踪:
- 测试调用端点(这已经是您的应用程序代码)
- 端点调用插件解析器
- 此插件抛出异常
这意味着您有两个选择:
- 你完全可以跳过那个测试。它不是您的应用程序逻辑的一部分,测试您正在使用的框架可能没有意义。
- 如果你真的想确定(因为例如,你正在弄乱带有自定义插件的
api
管道),而不是检查 400,你可以检查你的应用程序是否出现正确的错误:
assert_raise Plug.Parsers.ParseError, fn ->
conn
|> put_req_header("content-type", "application/json")
|> post(Routes.convert_path(conn, :convert), "invalid JSON")
end
只有在明确设置 conn 的情况下,您才明确测试 400。