hpjm
February 7, 2020, 10:04am
1
I’m trying to test a unique constraint but it is causing the following error:
(Postgrex.Error) ERROR 23502 (not_null_violation) null value in column "skill" violates not-null constraint
The same issue doesn’t occur during manual testing in dev.
The code which causes the error is here:
test "with same data does not insert twice" do
skill_fixture()
skill_fixture()
end
Related:
def skill_fixture(attrs \\ %{}) do
{:ok, skill} =
attrs
|> Enum.into(%{
skill: "dev"
})
|> Skills.create_skill()
skill
end
create table(:skills) do
add :skill, :string, null: false
add :created_by, references(:users, on_delete: :nilify_all)
timestamps()
end
create unique_index(:skills, [:skill])
def create_skill(attrs) do
%Skill{}
|> Skill.changeset(attrs)
|> Repo.insert(on_conflict: [set: [skill: attrs["skill"]]], conflict_target: :skill)
end
Did you do a rollback and edited the migration files? In that case test:
MIX_ENV=test mix.ecto.rollback
MIX_ENV=test mix.ecto.migrate
Or:
MIX_ENV=test mix.ecto.drop
MIX_ENV=test mix.ecto.create
MIX_ENV=test mix.ecto.migrate
hpjm
February 7, 2020, 3:49pm
3
andreaseriksson:
mix.ecto.rollback
Just tried both of those, unfortunately the issue persists
The errors refers to you skuill column form one of your tables. You set it to be null: false
. So you can’t insert something in that table unless you provide a value to the skill column as well. It can’t be null, that is why you get the error.
Also you probably have something like this in your migration
add :skills, :string, null: false
Now you can use default to have a value if you don’t give any value to skills like this
add :skills, :string, null: false, default: "my_cool_skill"
You also have a problem here
on_delete: :nilify_all
You can’t nilify
something that is not null.Use instead on_delete: :delete_all
As a side note take a look here https://hexdocs.pm/phoenix/contexts.html
I hope this helps
1 Like
That’s IMO because you don’t have a unique_constraint
specified in your Ecto schema file.
Can you show the code of your Skill.changeset
function?
hpjm
February 8, 2020, 11:32am
6
dimitarvp:
unique_constraint
I have a unique_constraint
hpjm
February 8, 2020, 11:33am
7
Thanks for spotting the bug. I don’t want a default value, so I’m allowing null now.
Not sure why there was no value being inserted, or why the issue only came up in tests, but now it’s not happening.
1 Like
Your fixture function passes the skill
attribute with an atom key:
{:ok, skill} =
attrs
|> Enum.into(%{
skill: "dev"
})
|> Skills.create_skill()
but your changeset looks for the value with a string key:
|> Repo.insert(on_conflict: [set: [skill: attrs["skill"]]], conflict_target: :skill)
So when this runs in test it’s actually doing:
|> Repo.insert(on_conflict: [set: [skill: nil]], conflict_target: :skill)
and tripping the null constraint.
hpjm
February 8, 2020, 4:48pm
9
@al2o3cr Thanks, well spotted, I didn’t catch that.