- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我很难对失败的测试进行故障排除,其中 conn.assigns 都是同一测试语句的一部分,但在测试的两行之间被清空。
我正在阅读“Programming Phoenix”,并重新编写代码以使其与 Phoenix 1.3 兼容。在其中 3 个测试中,存储在 conn.assigns 中的 :current_user 在测试过程中丢失,例如在 Controller 测试中的删除和获取之间丢失。
测试代码为:
describe "delete video" do
setup [:login_user, :create_video]
test "deletes chosen video", %{conn: conn, video: video} do
conn = delete conn, video_path(conn, :delete, video)
assert redirected_to(conn) == video_path(conn, :index)
assert_error_sent 404, fn ->
Logger.warn("Before get: #{inspect(conn.assigns)}")
conn = get conn, video_path(conn, :show, video)
Logger.warn("After get: #{inspect(conn.assigns)}")
conn
end
end
end
我添加了 Logger.warn 指令来检查 get 请求之前和之后的连接。在“Before get:”日志中,我仍然有一个带有 :current_user 键的 conn.assigns,但在随后的“After get”日志中,它消失了。
我最初认为我的身份验证机制对此负责,但随后我创建了一个日志插件来检查管道,并且我可以看到从调用 get 的管道开始,分配时缺少 current_user。
这是测试输出,显示管道开始/结束时的日志记录以及上面测试的日志。
ubuntu@ubuntu-xenial:~/rumbl$ MIX_ENV=test mix test test/rumbl_web/controllers/video_controller_test.exs:98
[info] Already up
Including tags: [line: "98"]
Excluding tags: [:test]
warning: module attribute @update_attrs was set but never used
test/rumbl_web/controllers/video_controller_test.exs:10
[debug] QUERY OK db=1.2ms
begin []
[debug] QUERY OK db=2.7ms
INSERT INTO "users" ("name","password_hash","username","inserted_at","updated_at") VALUES ($1,$2,$3,$4,$5) RETURNING "id" ["Some User", "$2b$12$0VvTPna8JMdSXcbNz2uvwOdhYWF/3ibhQ.gntdXqsb8v1TSeCZ0.K", "max", {{2017, 9, 22}, {10, 56, 53, 527902}}, {{2017, 9, 22}, {10, 56, 53, 529912}}]
[debug] QUERY OK db=0.1ms
commit []
[debug] QUERY OK db=0.1ms
begin []
[debug] QUERY OK db=1.1ms
INSERT INTO "videos" ("description","title","url","user_id","inserted_at","updated_at") VALUES ($1,$2,$3,$4,$5,$6) RETURNING "id" ["some description", "some title", "some url", 351, {{2017, 9, 22}, {10, 56, 53, 544069}}, {{2017, 9, 22}, {10, 56, 53, 544075}}]
[debug] QUERY OK db=0.1ms
commit []
[info] DELETE /manage/videos/274
[warn] Start of pipeline: %{current_user: %RumblWeb.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">, id: 351, inserted_at: ~N[2017-09-22 10:56:53.527902], name: "Some User", password: "supersecret", password_hash: "$2b$12$0VvTPna8JMdSXcbNz2uvwOdhYWF/3ibhQ.gntdXqsb8v1TSeCZ0.K", updated_at: ~N[2017-09-22 10:56:53.529912], username: "max", videos: #Ecto.Association.NotLoaded<association :videos is not loaded>}}
[warn] End of pipeline: %{current_user: %RumblWeb.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">, id: 351, inserted_at: ~N[2017-09-22 10:56:53.527902], name: "Some User", password: "supersecret", password_hash: "$2b$12$0VvTPna8JMdSXcbNz2uvwOdhYWF/3ibhQ.gntdXqsb8v1TSeCZ0.K", updated_at: ~N[2017-09-22 10:56:53.529912], username: "max", videos: #Ecto.Association.NotLoaded<association :videos is not loaded>}}
[warn] Start of authenticate_user: %{current_user: %RumblWeb.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">, id: 351, inserted_at: ~N[2017-09-22 10:56:53.527902], name: "Some User", password: "supersecret", password_hash: "$2b$12$0VvTPna8JMdSXcbNz2uvwOdhYWF/3ibhQ.gntdXqsb8v1TSeCZ0.K", updated_at: ~N[2017-09-22 10:56:53.529912], username: "max", videos: #Ecto.Association.NotLoaded<association :videos is not loaded>}}
[debug] Processing with RumblWeb.VideoController.delete/2
Parameters: %{"id" => "274"}
Pipelines: [:browser, :authenticate_user]
[debug] QUERY OK source="videos" db=0.9ms
SELECT v0."id", v0."description", v0."title", v0."url", v0."user_id", v0."category_id", v0."inserted_at", v0."updated_at" FROM "videos" AS v0 WHERE (v0."user_id" = $1) AND (v0."id" = $2) [351, 274]
[debug] QUERY OK db=0.1ms
begin []
[debug] QUERY OK db=0.3ms
DELETE FROM "videos" WHERE "id" = $1 [274]
[debug] QUERY OK db=0.0ms
commit []
[info] Sent 302 in 46ms
[warn] Before get: %{current_user: %RumblWeb.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">, id: 351, inserted_at: ~N[2017-09-22 10:56:53.527902], name: "Some User", password: "supersecret", password_hash: "$2b$12$0VvTPna8JMdSXcbNz2uvwOdhYWF/3ibhQ.gntdXqsb8v1TSeCZ0.K", updated_at: ~N[2017-09-22 10:56:53.529912], username: "max", videos: #Ecto.Association.NotLoaded<association :videos is not loaded>}}
[info] GET /manage/videos/274
[warn] Start of pipeline: %{}
[warn] End of pipeline: %{current_user: nil}
[warn] Start of authenticate_user: %{current_user: nil}
[info] Sent 302 in 2ms
[warn] After get: %{current_user: nil}
1) test delete video deletes chosen video (RumblWeb.VideoControllerTest)
test/rumbl_web/controllers/video_controller_test.exs:98
expected error to be sent as 404 status, but response sent 302 without error
code: assert_error_sent 404, fn ->
stacktrace:
(phoenix) lib/phoenix/test/conn_test.ex:600: Phoenix.ConnTest.assert_error_sent/2
test/rumbl_web/controllers/video_controller_test.exs:101: (test)
Finished in 0.6 seconds
8 tests, 1 failure, 7 skipped
Randomized with seed 982730
认证机制遵循本书的建议,如果 conn.assigns 中有 :current_user 则通过认证。设置 login_user 就是这样做的,在 :current_user 键下的 conn.assigns 中注入(inject)用户。在我的测试中,无论出于何种原因,由于 get 请求中的某个时刻 conn.assigns 为空,身份验证失败,用户被重定向到主页。
我不确定如何对删除语句和后续获取之间发生的情况进行故障排除。我查看了管道,但正如日志语句中所示, conn.assigns 在进入管道之前就被清空了。我预计 conn 在整个测试语句中不会改变,也许这是一个错误的假设。
回复Dogbert的评论:
Controller 测试中的login_user函数:
defp login_user(_) do
user = insert_user(username: "max")
conn = assign(build_conn(), :current_user, user)
{:ok, conn: conn, user: user}
end
在auth Controller 中调用函数:
def call(conn, repo) do
user_id = get_session(conn, :user_id)
cond do
user = conn.assigns[:current_user] ->
conn
user = user_id && repo.get(RumblWeb.User, user_id) ->
assign(conn, :current_user, user)
true ->
assign(conn, :current_user, nil)
end
end
最佳答案
这是由phoenix回收引起的,参见( https://hexdocs.pm/phoenix/1.3.0/Phoenix.ConnTest.html#module-recycling )
浏览器通过使用cookie来实现存储。当在响应中设置 cookie 时,浏览器会存储它并在下一个请求中发送它。
为了模拟这种行为,该模块提供了回收的想法。 recycle/1 函数接收一个连接并返回一个新连接,类似于 conn/0 返回的连接,并将前一个连接的所有响应 cookie 定义为请求 header 。这在测试需要 cookie 或 session 才能工作的多个路由时非常有用。
请记住,Phoenix 会自动回收调度之间的连接。大多数情况下这通常效果很好,但如果您在下一次调度之前修改连接,它可能会丢弃信息:
# No recycling as the connection is fresh
conn = get build_conn(), "/"
# The connection is recycled, creating a new one behind the scenes
conn = post conn, "/login"
# We can also recycle manually in case we want custom headers
conn =
conn
|> recycle()
|> put_req_header("x-special", "nice")
# No recycling as we did it explicitly
conn = delete conn, "/logout"
回收还会回收“accept” header 。
要保留分配
,您可以在调用delete
和get
之间手动回收和分配:
saved_assigns = conn.assigns
conn =
conn
|> recycle()
|> Map.put(:assigns, saved_assigns)
关于elixir - 在测试过程中丢失 conn.assigns,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46363292/
我正在创建一个管理外部实用程序的多个实例的应用程序,为每个实例提供数据并获取结果。 但是我在编写单元测试时遇到了问题。 如何测试目标方法在被调用时是否真的启动了一个进程(通过属性设置)? 我试过: 让
我意识到“标准”这个词很奇怪,因为测试似乎非常依赖于项目,但是如果我设计了一个非常标准的场景,我希望得到关于我应该关注的测试类型的反馈。 我的团队正在创建一个中型数据驱动的 Web 应用程序。我们正在
在我的设置中,我运行了一个脚本 火车一个模型并开始生成检查点。另一个脚本监视新的检查点和 评估 他们。脚本并行运行,因此评估只是训练之后的一步。 支持这种情况的正确 Tracks 配置是什么? 最佳答
Jenkins三大概念: Job:即为任务 插件:maven构建项目、git拉取代码、ssh插件 工作空间:任务的存储空间,即为git代码的存储空间 开发
我是一名优秀的程序员,十分优秀!