2016-09-11 4 views
3

Ich versuche, Einzigartigkeit in meiner Datenbank zu testen, und ich habe ein wenig Probleme. Ich lief diese Migration:So testen Sie die Eindeutigkeitsbeschränkung mit Ecto

def change do 
    create table(:signups) do 
    add :name, :string 
    add :email, :string 

    timestamps() 
    end 

    create unique_index(:signups, [:email]) 
end 

haben diese changeset def in meinem Modell:

test "duplicate email changeset is invalid" do 
    %Signup{} 
    |> Signup.changeset(@valid_attrs) 
    |> Repo.insert! 

    user2 = %Signup{} 
    |> Signup.changeset(@valid_attrs) 
    assert {:error, _changeset} = Repo.insert(user2) 
end 

Der zweite Einsatz durch, obwohl zu gehen scheint:

def changeset(struct, params \\ %{}) do 
    struct 
    |> cast(params, [:name, :email]) 
    |> validate_required([:name, :email]) 
    |> validate_format(:email, ~r/@/) 
    |> update_change(:email, &String.downcase/1) 
    |> unique_constraint(:email) 
end 

und den durchgeführten Test ist hat versagt es sollte nicht. Der genaue Fehler ist:

1) test duplicate email changeset is invalid (EventSignup.SignupTest) 
    test/models/signup_test.exs:24 
    match (=) failed 
    code: {:error, _changeset} = Repo.insert(user2) 
    rhs: {:ok, 
      %EventSignup.Signup{__meta__: #Ecto.Schema.Metadata<:loaded, "signups">, 
      email: "[email protected]", id: 41, 
      inserted_at: #Ecto.DateTime<2016-09-11 19:35:40>, 
      name: "some content", 
      updated_at: #Ecto.DateTime<2016-09-11 19:35:40>}} 
    stacktrace: 
     test/models/signup_test.exs:31: (test) 

Kann jemand sehen, was ich hier vermisse? Wenn ich manuell zwei gleiche Datensätze über iex einfüge, wird der zweite Einfügevorgang fehlschlagen, aber während des Tests passiert er.

+1

Sind Sie sicher, dass diese Einschränkung in der Testdatenbank existiert? Vielleicht haben Sie die Testdatenbank migriert, bevor Sie die Einschränkung hinzugefügt haben? Versuchen Sie, die Testdatenbank erneut zu löschen, zu erstellen und zu migrieren ("MIX_ENV = Testmix do ecto.drop, ecto.create, ecto.migrate") und führen Sie dann die Tests durch. – Dogbert

+1

@Dogbert du hattest recht. Dieser Fehler kam von mir, weil ich nicht wusste, dass es eine separate Testdatenbank gab und dass ein Standardmix ecto.rollback, mix ecto.migrate nicht das Hinzufügen der einmaligen Einschränkung zu der Migration zu einem späteren Zeitpunkt abdecken würde. Lektion gelernt. Sie waren zuerst mit einer Weile, also wenn Sie dies als Antwort setzen, werde ich glücklich sein, es zu akzeptieren. – targaf

Antwort

1

Führen Sie iex in der Testumgebung MIX_ENV=test iex -S mix aus und versuchen Sie, zwei Datensätze mit demselben Wert einzufügen. Wenn Sie dies zulassen, bedeutet dies, dass Ihre Testdatenbank unique_index fehlt. Wichtig! Denken Sie daran, Ihre Testdatenbank danach zu säubern.

Alternativ:
Überspringen Sie die Beschreibung oben und führen Sie MIX_ENV=test mix ecto.reset dann führen Sie Ihre Tests noch einmal. Wenn sie Ihren Test bestanden, fehlte db unique_index.

+0

btw ecto.reset ist Alias ​​für [ecto.drop, ecto.create, ecto.migrate] – amatalai

4

Ich denke, Ihre Migration und Ihr Modell sind korrekt. Aber sieht aus, als ob Sie = on assert macro verwenden, wenn Sie so etwas tun sollten:

Hier ist mein Test funktioniert.

test "only one setting per company" do 
    first_setting = insert(:setting) 
    second_setting = params_for(:setting, %{company_id: first_setting.company.id}) 
    changeset = Setting.changeset(%Setting{}, second_setting) 
    {:error, changeset} = Repo.insert changeset 
    assert changeset.errors == [company_id: {"has already been taken", []}] 
    refute changeset.valid? 
end 

Der Einsatz ist eine Hilfsmethode aus ex-machina, die ein gültiges Modell erstellt und die params Rück eine gültige Karte mit dem gleichen company_id der Fehler passieren zu erzwingen.