2015-08-13 12 views
14

Ho un test che deve impostare user_id alla sessione prima del test, perché questa azione deve conoscere l'utente corrente.Come posso impostare la sessione in configurazione quando eseguo l'azione phoenix che richiede user_id in sessione?

setup do 
    %User{ 
    id: 123456, 
    username: "lcp", 
    email: "[email protected]", 
    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 

Ho provato questo codice, ma si dice che session not fetched, call fetch_session/2.


web/controller/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 

Aggiornato

ottengo nulla quando ottengo user_id dalla sessione attraverso Conn.get_session(conn, :user_id).

Ecco regolatore postale web/controller/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 

E 'il mio file di prova.

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: "[email protected]", 
     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 


aggiornamento ..


lib/simple_blog/candele/authenticated.ex

definisco una spina autenticato

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 

nella mia prova

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." 

ora, il test è superato.

risposta

11

In realtà non è possibile farlo in questo modo a causa dell'azione post che ripristina la sessione. Hai un paio di opzioni.

Innanzitutto, è possibile eseguire un test di integrazione che visita il percorso di accesso con credenziali valide e quindi effettuare la richiesta per creare il post.

In secondo luogo, è possibile creare un tappo di autenticazione come questo:

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 

è possibile verificare questo facendo qualcosa di simile a quanto segue tratto dal Phoenix tests:

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: "[email protected]", 
     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 

È ora possibile verificare la periferica facendo:

setup do 
    %User{ 
    id: 123456, 
    username: "lcp", 
    email: "[email protected]", 
    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 
+0

Ho provato, ma non posso ottenere user_id dalla sessione. – LcpMarvel

+0

'Plug.Conn.get_session (conn,: user_id)' – LcpMarvel

+0

http://hexdocs.pm/plug/Plug.Conn.html#get_session/2 - il codice è corretto. Potresti pubblicare più del tuo codice per vedere qual è il problema? – Gazler

2

Un altro modo semplice è utilizzare assigns e caricare pigramente i dati dalla sessione.Durante il test di integrazione, i dati della sessione verranno caricati, ma durante il test delle unità si può semplicemente assegnare i dati:

# controller code 
def success(conn, _params) do 
    conn 
    |> assign(:username, conn.assigns[:username] || get_session(conn, :username)) 
    |> render("auth_success.html") 
end 

# test 
test "it renders success page with username and token", %{conn: conn} do 
    conn = conn 
    |> assign(:username, "unpredictablestring") 
    |> get("/portal/success") 

    assert html_response(conn, 200) =~ "unpredictablestring" 
end 

di credito va a @carp dai commenti, ho solo pensato che questo meritava di essere pubblicato come risposta

Problemi correlati