2016-09-11 2 views
3

Я пытаюсь проверить уникальность в моей базе данных, и у меня небольшие проблемы. Я запустил эту миграцию:Как проверить ограничение уникальности с помощью Ecto

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

    timestamps() 
    end 

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

есть это набора изменений размораживания в моей модели:

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 

и тест, который неисправный является:

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 

Второй вставка, кажется, идет через несмотря на то, это не должно. Полученная точная ошибка:

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) 

Кто-нибудь видит, что мне здесь не хватает? Если я вручную вставлю две из тех же записей через iex, вторая вставка потерпит неудачу, но во время теста она пройдет.

+1

Вы уверены, что это ограничение существует в тестовой базе данных? Может быть, вы перенесли тестовую базу данных, прежде чем добавлять ограничение? Попробуйте снова сбросить, создать и перенести тестовую базу данных («MIX_ENV = test mix do ecto.drop, ecto.create, ecto.migrate'), а затем запустить тесты. – Dogbert

+1

@Dogbert ты был прав. Эта ошибка возникла из-за того, что я не знал, что существует отдельная тестовая база данных, и что стандартная смесь ecto.rollback, mix ecto.migrate не будет охватывать добавление уникального ограничения для переноса позднее. Урок выучен. Вы были первыми, поэтому, если вы поместите это как ответ, я буду рад принять его. – targaf

ответ

1

Запустите iex в тестовой среде MIX_ENV=test iex -S mix и попробуйте вставить две записи с одинаковым значением. Если это позволяет сделать это, это означает, что в тестовой базе данных отсутствует уникальный_индекс. Важно! Не забудьте очистить тестовую базу данных позже.

В качестве альтернативы:
Пропустите описание выше и запустите MIX_ENV=test mix ecto.reset, затем запустите свои тесты еще раз. Если они проходят тест, в db отсутствует уникальный_индекс.

+0

btw ecto.reset является псевдонимом для [ecto.drop, ecto.create, ecto.migrate] – amatalai

4

Я думаю, что ваша миграция и модель верны. Но похоже, что вы используете = on assert macro, когда вы должны сделать что-то вроде:

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

    user2 = %Signup{} 
    |> Signup.changeset(@valid_attrs) 

    {:error, changeset} = Repo.insert(user2) 
    refute changeset.valid? 
end 

Вот мой тест.

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 

Вкладыш представляет собой вспомогательный метод из ex-machina, что создает действительную модель и PARAMS возвращает действительную карту с тем же company_id заставить ошибки случаются.

Смежные вопросы