Skip to content

Instantly share code, notes, and snippets.

@rosswilson
Created February 7, 2018 19:39
Show Gist options
  • Save rosswilson/67b5faa77c7ca0fac0fe6f5995917af4 to your computer and use it in GitHub Desktop.
Save rosswilson/67b5faa77c7ca0fac0fe6f5995917af4 to your computer and use it in GitHub Desktop.
Elixir Test Factory Pattern
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
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
@rosswilson
Copy link
Author

rosswilson commented Feb 7, 2018

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"})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment