Using Custom Attributes in ExMachina Factories
It’s finally here! With the newest v2.3.0
release of ex_machina
, we can finally
customize how factories are called and built in Elixir. After a long, long discussion
on Github, the team decided to add a secondary method of defining factories by passing in a list
of attributes, which can be used however you like.
Here’s how a normal factory definition looks like:
def post_factory do
title = sequence(:title, &"Blog Post #{&1}")
author = build(:user)
%Post{
title: title,
slug: Post.slug_from(title),
author: author,
blog: author.blog,
}
end
But if you attempt to pass in a custom value for title when calling the factory, the slug would not reflect the passed title, unless you also pass in the slug:
insert(:post, title: "A different blog post")
Similarly, passing in a custom user would cause the Factory to be invalid because :blog
will
reference the blog of a different user that the definition automatically built:
custom_author = insert(:user, ...)
insert(:post, author: custom_author)
With the new update, you can write factory definitions with an arity of 1, receiving the inputs and building the factory according to them:
def post_factory(attrs) do
title = attrs[:title] || sequence(:title, &"Blog Post #{&1}")
author = Map.get_lazy(attrs, :author, fn -> insert(:user) end)
post =
%Post{
title: title,
slug: Post.slug_from(title),
author: author,
blog: author.blog,
}
merge_attributes(post, attrs)
end
There’s a lot more that’s possible with the new release, all of which I cover in a post on the Slab blog. You can check it out here →