FactoryMan

Elixir test data factories with automatic struct building, database insertion, and customizable hooks.

Installation

Add FactoryMan to your mix.exs dependencies:

def deps do
  [
    {:factory_man, "0.1.0"}
  ]
end

Then run mix deps.get.

Quick Start

Create a factory module in your test support directory:

defmodule MyApp.Factories.Users do
  use FactoryMan, repo: MyApp.Repo

  alias MyApp.Users.User

  deffactory user(params \\ %{}), struct: User do
    base_params = %{username: "user-#{System.os_time()}"}

    Map.merge(base_params, params)
  end
end

Build and insert in tests:

# Build a struct (not persisted)
iex> MyApp.Factories.Users.build_user_struct(%{username: "test_user"})
%User{id: nil, username: "test_user"}

# Insert into database
iex> MyApp.Factories.Users.insert_user!(%{username: "test_user"})
%User{id: 1, username: "test_user"}

# Insert multiple records
iex> MyApp.Factories.Users.insert_user_list!(3)
[%User{id: 1, ...}, %User{id: 2, ...}, %User{id: 3, ...}]

Base Factory Pattern (Optional)

For larger projects, you may want to share common configuration across multiple factory modules. Create a base factory module with shared settings:

defmodule MyApp.Factory do
  # Define base factory options, which can be extended in child factories:
  use FactoryMan,
    repo: MyApp.Repo

  # Helper functions available to all child factories
  def generate_username, do: "user-#{System.os_time()}"
end

Then extend the base factory in child factory modules:

defmodule MyApp.Factories.Users do
  use FactoryMan, extends: MyApp.Factory

  alias MyApp.Users.User

  deffactory user(params \\ %{}), struct: User do
    %{username: generate_username()} |> Map.merge(params)
  end
end

defmodule MyApp.Factories.Posts do
  use FactoryMan, extends: MyApp.Factory

  alias MyApp.Posts.Post
  alias MyApp.Factories.Users

  deffactory post(params \\ %{}), struct: Post do
    base_params = %{
      title: "Test Post",
      author_id: params[:author_id] || Users.insert_user!().id
    }

    Map.merge(base_params, params)
  end
end

This pattern is optional - use whatever structure fits your project.

Features

Documentation

Full documentation is available in the FactoryMan module: