Params_with_assocs not overriding nil value - Exmachina

params_with_assocs not overriding nil value

def comment_factory(attrs \\ %{}) do

    %Comment{
      body: attrs[:body] || Faker.Lorem.sentence(),
      post: attrs[:post] || build(:post)
}
end

In my test file,

@attrs params_with_assocs(
        :comment,
        %{
          body: nil
})

This seems to still return

%{
  body: "Veritatis nam voluptatem voluptatem rerum",
  post_id: "69244d42-fd03-41af-9910-9bac7b966ba5"
}

Why is params_with_assocs not able to override body with nil value?

I stopped working with ex_machina a while ago but have you considered using delayed attribute evaluation, just a blind shot in the dark?

@attrs params_with_assocs(:comment, %{body: fn -> nil end})

Not even sure it will work but I seem to remember using those functions so as to delay attribute evaluation.

Thank you, I haven’t tried delayed attribute evaluation before, will research about it. But any idea on what is causing this issue? Is it because attrs[:body] is nil so it evaluates the other side of the OR?

Also in this case,

def comment_factory(attrs \\ %{}) do

    %Comment{
      body: Faker.Lorem.sentence(),
      post: build(:post)
}
end

does exmachina by behavior override the body if I do

@attrs params_with_assocs(
        :comment,
        %{
          body: "Veritatis voluptatem rerum"
})

or does it require attrs[:body] to override the body in factory?

I can’t remember now – sorry. I could only theorize that nil isn’t deemed a valid attribute value? But that wouldn’t make sense.

I stopped using ex_machina in favour of domain/business-specific modules that create objects, which increased certainty factor in tests as well. You can add a very thin layer on top of that that imitates ex_machina if you really need the random data.

If you pass %{body: nil} in attrs, the right-hand side of the || will be used.

If you want to reliably check “does the map have this key?” use Map.get or similar instead:

body: Map.get_lazy(attrs, :body, fn -> Faker.Lorem.sentence() end),

get_lazy is useful here since Faker.Lorem does a little calculation and isn’t needed if :body is provided.

1 Like