2016-04-20 7 views
3

Beim Testen von Controllern kann es nützlich sein, einige Daten in der Testdatenbank zu haben. Und manchmal möchten Sie vielleicht die Datenerstellung testen. Was ist der richtige Weg dies einzurichten? Ein Test für Controller sollte testen, ob die create Funktion des Controllers funktioniert, nicht das Modell.Elixier: Wie Phoenix Controller zu testen, wenn sie Datensätze in der Datenbank benötigen? Mit Samen oder Spott?

Als Beispiel möchte ich einen Session-Controller testen und ich habe zwei Tests. Einer testet, dass ein erstellter Benutzer sich anmelden kann. Der andere kann er nicht, wenn das Passwort falsch ist. Beide verlassen sich darauf, dass ein Benutzer in der Datenbank ist. Wie ich damit jetzt umgehen ist, den Benutzer erstellen zuerst:

defmodule MyApp.SessionControllerTest do 
    use MyApp.ConnCase 

    alias MyApp.Admin 
    @valid_attrs %{email: "[email protected]", name: "John Doe", password: "goodpassword", password_confirmation: "goodpassword", password_hash: "somecontent", username: "username"} 
    @invalid_attrs %{} 

    setup do 
    {:ok, conn: put_req_header(conn, "accept", "application/json")} 
    end 

    test "admin can login after creation" do 
    conn = post conn, admin_path(conn, :create), admin: @valid_attrs 
    body = json_response(conn, 201) 
    assert Repo.get_by(Admin, email: @valid_attrs[:email]) 
    conn = post conn, session_path(conn, :create), %{data: %{attributes: %{email: @valid_attrs[:email], password: @valid_attrs[:password]}}} 
    body = json_response(conn, 201) 
    assert body["data"]["token"] 
    end 

    test "login with wrong password returns an error" do 
    conn = post conn, session_path(conn, :create), %{data: %{attributes: %{email: @valid_attrs[:email], password: "wrongpassword"}}} 
    body = json_response(conn, 403) 
    assert body["error"] 
    end 

end 

Wenn ich jetzt hinzufügen eine Einzigartigkeit auf meinem Admin Modell zurückhalten diese potentiell chaotisch könnte, da, wenn ich einen Benutzer in der Datenbank müssen muss ich sicherstellen, dass dass der Test nicht aufgrund dieser Einschränkung fehlschlägt, sondern weil etwas im getesteten Controller falsch ist. Es ist auch nicht klar, in welcher Reihenfolge die Tests durchgeführt werden, und es ist wie ein Alptraum, mit der Datenerstellung über mehrere Tests hinweg übereinzustimmen.

Ich möchte entweder einen Ort, wo ich am Anfang definieren, welche Daten erstellt werden. Oder verwenden Sie Mocks für den Controller-Test.

Wie ist das möglich?

Antwort

8

Verwenden Sie die Funktion setup, um einige Daten zu Ihrer Datenbank hinzuzufügen.

setup do 
    Repo.insert!(%User{id: 1, password: "somepassword", ....}) 
    .... 
    :ok 
end 

Die setup wird vor jedem Test aufgerufen werden. Weitere Informationen finden Sie unter ExUnit hexdocs.

Um die Tests Schritt für Schritt im Synchronmodus auszuführen, fügen Sie async: false hinzu, um den Anruf zu verwenden.

defmodule MyApp.SessionControllerTest do 
    use MyApp.ConnCase, async: false` 

Aber ich denke, es ist besser, die Tests ohne Abhängigkeiten zu anderen Tests auszuführen.

defmodule MyApp.SessionControllerTest do 
    use MyApp.ConnCase 

    alias MyApp.Admin 
    @valid_attrs %{email: "[email protected]", name: "John Doe", password: "goodpassword", password_confirmation: "goodpassword", password_hash: "somecontent", username: "username"} 
    @invalid_attrs %{} 

    setup do 
    Repo.insert!(%User{email: "[email protected]", password: "somepassword", ....}) 
    {:ok, conn: put_req_header(conn, "accept", "application/json")} 
    end 

    ... 

    test "login with wrong password returns an error" do 
    conn = post conn, session_path(conn, :create), %{data: %{attributes: %{email: "[email protected]", password: "wrongpassword"}}} 
    body = json_response(conn, 403) 
    assert body["error"] 
    end 

end 

Ich hoffe, es hilft.

+5

Da ein Teil seiner Frage Es ging um die Isolation zwischen den Tests, es ist vielleicht erwähnenswert, dass Ecto 2 (derzeit in der Betaversion) gleichzeitige Datenbanktests in einem Sandbox-Umgebung. –

+0

@CodyPoll: Das ist ein sehr netter Hinweis –

1

Ein bisschen spät auf die Party, aber es könnte anderen helfen.

Ich würde vorschlagen, eine ex_machina Fabrikbibliothek zu verwenden. https://github.com/thoughtbot/ex_machina Mit diesem können Sie Testdaten an einem Ort definieren und erstellen.

definieren Fabriken wie so:

defmodule MyApp.Factory do 
    # with Ecto 
    use ExMachina.Ecto, repo: MyApp.Repo 

    # without Ecto 
    use ExMachina 

    def user_factory do 
    %MyApp.User{ 
     name: "Jane Smith", 
     email: sequence(:email, &"email-#{&1}@example.com"), 
    } 
    end 

    def article_factory do 
    %MyApp.Article{ 
     title: "Use ExMachina!", 
     # associations are inserted when you call `insert` 
     author: build(:user), 
    } 
    end 

    def comment_factory do 
    %MyApp.Comment{ 
     text: "It's great!", 
     article: build(:article), 
    } 
    end 
end 

Und wäre ein Datensatz erstellt:

insert(:comment, article: article) 

Sie können auch einen Datensatz (nicht gespeicherten) bauen

build(:user) 
+0

Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz bereitzustellen.Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert. - [Aus Bewertung] (/ review/low-quality-posts/14902448) –

+1

Änderte meine Antwort, hoffe, das ist besser. –

Verwandte Themen