当我在 session 中测试需要 user_id 的 phoenix action 时,如何在 setup 中设置 session? [英] how can i set session in setup when i test phoenix action which need user_id in session?

查看:23
本文介绍了当我在 session 中测试需要 user_id 的 phoenix action 时,如何在 setup 中设置 session?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个测试,需要在测试前将 user_id 设置为 session,因为此操作需要知道 current_user.

I have a test which need to set user_id to session before testing, because this action need to know the current_user.

setup do
  %User{
    id: 123456,
    username: "lcp",
    email: "abc@gmail.com",
    password: Comeonin.Bcrypt.hashpwsalt("password")
  } |> Repo.insert

  {:ok, user: Repo.get(User, 123456) }
end

test "POST /posts", context do
  # conn = conn()
  #      |> put_session(:user_id, context[:user].id)
  #      |> post("/posts", %{ post: %{ title: "title", body: "body" } })

  # assert get_flash(conn, :info) == "Post created successfully."

  # updated to => 
  conn = conn()
        |> Map.put(:secret_key_base, String.duplicate("abcdefgh", 8))
        |> Plug.Session.call(@session)
        |> Plug.Conn.fetch_session
        |> put_session(:user_id, context[:user].id)
        |> post("/posts", %{ post: %{ title: "title", body: "body" } })

  assert get_flash(conn, :info) == "Post created successfully."
end

我已经尝试过这段代码,但它说 session not fetched,调用 fetch_session/2.

I have tried this code, but it says that session not fetched, call fetch_session/2.

web/controllers/controller_helper.ex

web/controllers/controller_helper.ex

defmodule SimpleBlog.ControllerHelpers do    
  alias Phoenix.Controller
  alias Plug.Conn
  alias SimpleBlog.Router.Helpers

  def authenticate(conn, _) do
    case Conn.get_session(conn, :user_id) do
      nil ->
        unauthorized(conn)
      user_id ->
        case SimpleBlog.Repo.get(SimpleBlog.User, user_id) do
          {:ok, user} ->
            Conn.assign(conn, :current_user, user)
          nil ->
            unauthorized(conn)
        end
    end
  end

  def unauthorized(conn) do
    conn
      |> Controller.put_flash(:error, "You must be logged in")
      |> Controller.redirect(to: Helpers.session_path(conn, :new))
      |> Conn.halt
  end
end

更新

当我通过 Conn.get_session(conn, :user_id) 从会话中获取 user_id 时,我得到 nil.

I get nil when i get user_id from session through Conn.get_session(conn, :user_id).

这是后控制器web/controllers/post_controller.ex

Here is post controller web/controllers/post_controller.ex

defmodule SimpleBlog.PostController do
  use SimpleBlog.Web, :controller
  import SimpleBlog.ControllerHelpers

  alias SimpleBlog.Post

  plug :authenticate when not action in [:new]

  def create(conn, %{ "post" => post_params }) do
    changeset = Post.changeset(%Post{}, post_params)

    case Repo.insert(changeset) do
      {:ok, _post} ->
        conn
          |> put_flash(:info, "Post created successfully.")
          |> redirect(to: post_path(conn, :new))
      {:error, changeset} ->
        render(conn, "new.html", changeset: changeset)
    end
  end
end

这是我的测试文件.

defmodule SimpleBlog.PostControllerTest do
  use SimpleBlog.ConnCase
  alias SimpleBlog.Repo
  alias SimpleBlog.User

  @session Plug.Session.init(
    store: :cookie,
    key: "_app",
    encryption_salt: "yadayada",
    signing_salt: "yadayada"
  )

  setup do
    %User{
      id: 123456,
      username: "lcp",
      email: "abc@gmail.com",
      password: Comeonin.Bcrypt.hashpwsalt("password")
    } |> Repo.insert

    {:ok, user: Repo.get(User, 123456) }
  end


  @tag timeout: 900000
  test "POST /posts", context do
    conn = conn()
            |> Map.put(:secret_key_base, String.duplicate("abcdefgh", 8))
            |> Plug.Session.call(@session)
            |> Plug.Conn.fetch_session
            |> put_session(:user_id, context[:user].id)
            |> post("/posts", %{ post: %{ title: "title", body: "body" } })

    assert get_flash(conn, :info) == "Post created successfully."
  end
end



更新..



update ..

lib/simple_blog/plugs/authenticated.ex

lib/simple_blog/plugs/authenticated.ex

我定义了一个插件认证

defmodule SimpleBlog.Plugs.Authenticated do
  import Plug.Conn
  alias Phoenix.Controller
  alias SimpleBlog.Router.Helpers
  alias SimpleBlog.User

  def init(options) do
    options
  end

  def call(conn, _) do
    case conn |> current_user_id do
      nil ->
        conn
          |> Controller.put_flash(:error, "You must be logged in")
          |> Controller.redirect(to: Helpers.session_path(conn, :new))
          |> halt
      current_user_id ->
        conn |> assign(:current_user, SimpleBlog.Repo.get(User, current_user_id))
    end
  end

  defp current_user_id(conn) do
    case Mix.env do
      :test ->
        conn.private[:authenticated_current_user_id]
      _ ->
        conn |> fetch_session |> get_session(:current_user_id)
    end
  end
end

在我的测试中

conn = conn()
        |> put_private(:authenticated_current_user_id, context[:user].id)
        |> post("/posts", %{ post: %{ title: "title", body: "body" } })

assert get_flash(conn, :info) == "Post created successfully."

现在,测试通过了.

推荐答案

您实际上不能这样做,因为 post 操作会重置会话.您有几个选择.

You actually can't do it like this due to the post action resetting the session. You have a couple of options.

首先,您可以进行集成测试,使用有效凭据访问您的登录路径,然后提出创建帖子的请求.

First, you can do an integration test that visits your login path with valid credentials, and then make your request to create the post.

其次,您可以像这样创建一个身份验证插件:

Secondly, you can create an authentication plug like this:

defmodule SimpleBlog.Plug.Authenticate do
  import Plug.Conn
  alias SimpleBlog.Router.Helpers, as: RouteHelpers
  import Phoenix.Controller

  alias SimpleBlog.Repo
  alias SimpleBlog.User

  def init(opts), do: opts

  def call(conn, _opts) do
    if user = get_user(conn) do
      assign(conn, :current_user, user)
    else
      auth_error!(conn)
    end
  end

  def get_user(conn) do
    case conn.assigns[:current_user] do
      nil      -> fetch_user(conn)
      user     -> user
    end
  end

  defp fetch_user(conn) do
    case get_session(conn, :current_user) |> find_user
      {:ok, user} -> user
      _           -> nil
    end
  end

  defp find_user(id) when do
    Repo.get(User, id)
  end

  defp auth_error!(conn) do
    conn
    |> put_flash(:error, "You need to be signed in to view this page")
    |> redirect(to: RouteHelpers.session_path(conn, :new))
    |> halt
  end
end

您可以通过从 凤凰测试:

defmodule SimpleBlog.Plug.AuthenticationTest do
  use ExUnit.Case
  use Plug.Test

  alias Plug.Conn
  alias SimpleBlog.Plug.Authenticate
  alias SimpleBlog.Repo
  alias SimpleBlog.User
  import SimpleBlog.Router.Helpers

  @session Plug.Session.init(
    store: :cookie,
    key: "_app",
    encryption_salt: "yadayada",
    signing_salt: "yadayada"
  )

  setup do
    user = %User{
      id: 123456,
      username: "lcp",
      email: "abc@gmail.com",
      password: Comeonin.Bcrypt.hashpwsalt("password")
    } |> Repo.insert!

    session_data = %{id: user.id}
    conn =
      conn(:get, "/")
      |> Map.put(:secret_key_base, String.duplicate("abcdefgh", 8))
      |> Plug.Session.call(@session)
      |> Conn.fetch_session()
    {:ok, conn: conn, user: user, session_data: session_data}
  end

  test "get_user returns the user if it is set in conn.assigns", %{conn: conn, user: user} do
    conn = Conn.assign(conn, :current_user, user)
    assert Authenticate.get_user(conn) == user
  end

  test "get_user returns the user if it is set in a session", %{conn: conn, user: user, session_data: session_data} do
    conn = Conn.put_session(conn, :current_user, session_data)
    assert Authenticate.get_user(conn) == user
  end

  test "get_user returns nil if the user is not in assigns or session", %{conn: conn} do
    assert Authenticate.get_user(conn) == nil
  end

  test "when there is not user stored", %{conn: conn} do
    conn =
      |> Phoenix.Controller.fetch_flash
      |> Authenticate.call([])
    assert Phoenix.Controller.get_flash(new_conn, :error) == "You need to be signed in to view this page"
    assert Phoenix.ConnTest.redirected_to(new_conn) == session_path(new_conn, :new)
  end
end

您现在可以通过执行以下操作来测试您的控制器:

You can now test your controller by doing:

setup do
  %User{
    id: 123456,
    username: "lcp",
    email: "abc@gmail.com",
    password: Comeonin.Bcrypt.hashpwsalt("password")
  } |> Repo.insert

  {:ok, user: Repo.get(User, 123456) }
end

test "POST /posts", %{user: user} do
   conn = conn()
        |> assign(:current_user, user)
        |> post("/posts", %{ post: %{ title: "title", body: "body" } })

   assert get_flash(conn, :info) == "Post created successfully."
end

这篇关于当我在 session 中测试需要 user_id 的 phoenix action 时,如何在 setup 中设置 session?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆