Created
February 7, 2018 19:39
-
-
Save rosswilson/67b5faa77c7ca0fac0fe6f5995917af4 to your computer and use it in GitHub Desktop.
Elixir Test Factory Pattern
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule MyApp.Factory do | |
use MyApp.Faker, repo: MyApp.Repo | |
def user_factory do | |
%MyApp.Users.User{ | |
name: "Some name", | |
email: "some-name@example.com" | |
} | |
end | |
def asset_type_factory do | |
%MyApp.Assets.AssetType{ | |
name: "Some name", | |
description: "Some description" | |
} | |
end | |
def asset_factory do | |
%MyApp.Assets.Asset{ | |
barcode: "some-barcode", | |
cost: "Some cost", | |
department: "Some department", | |
status: "initial", | |
asset_type: build(:asset_type) | |
} | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule MyApp.Faker do | |
defmacro __using__(opts) do | |
repo = Keyword.get(opts, :repo) | |
quote do | |
def build(factory_name, attrs \\ %{}) do | |
MyApp.Faker.build(__MODULE__, factory_name, attrs) | |
end | |
def insert(factory_name, attrs \\ %{} ) do | |
built = MyApp.Faker.build(__MODULE__, factory_name, attrs) | |
unquote(repo).insert(built, prefix: "tenant_id") | |
end | |
end | |
end | |
def build(module, factory_name, attrs \\ %{}) do | |
attrs = Enum.into(attrs, %{}) | |
function_name = build_function_name(factory_name) | |
apply(module, function_name, []) |> do_merge(attrs) | |
end | |
defp build_function_name(factory_name) do | |
factory_name | |
|> Atom.to_string | |
|> Kernel.<>("_factory") | |
|> String.to_atom | |
end | |
defp do_merge(%{__struct__: _} = record, attrs), do: struct!(record, attrs) | |
defp do_merge(record, attrs), do: Map.merge(record, attrs) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
An example of a simple Elixir test factory that I'm using to generate fake data for tests. Like ex_machina but supports the multi-tenant database postgres prefix-based architecture that I'm using.
Used like:
Builds an instance of the User struct
MyApp.factory.build(:user)
Builds and inserts an instance of the User struct
MyApp.factory.insert(:user)
Builds and inserts an instance of the User struct, with the name attribute overridden
MyApp.factory.insert(:user, %{name: "Ross Wilson"})