FactoryMan

An Elixir library for generating test data. Define factories with deffactory, and FactoryMan generates functions for building params, structs, and database records.

Inspired by ExMachina, but with a different API and feature set.

Installation

Add FactoryMan to your mix.exs dependencies:

def deps do
[
{:factory_man, "~> 0.17.0", only: [:dev, :test]}
]
end

Then run mix deps.get.

Quick Tour

Define factories:

defmodule MyApp.Factory do
# `strict: true` raises on misspelled keys and on params a factory body ignores
use FactoryMan, repo: MyApp.Repo, strict: true
alias MyApp.Accounts.User
alias MyApp.Blog.{Post, Tag}
# Basic factory (struct-ful)
deffactory user(params \\ %{}), struct: User do
base_params = %{
username: FactoryMan.sequence("user"),
email: FactoryMan.sequence(:email, fn n -> "user#{n}@example.com" end),
role: FactoryMan.sequence(:role, ["admin", "mod", "user"]),
joined_at: fn -> DateTime.utc_now() end,
display: fn user -> "#{user.username} (#{user.role})" end
}
Map.merge(base_params, params)
end
# Variant: Preprocesses params, then delegates to the base factory
defvariant admin(params \\ %{}), for: :user do
base_params = %{role: "admin"}
Map.merge(base_params, params)
end
defvariant confirmed(params \\ %{}), for: :user do
Map.merge(%{confirmed_at: fn -> DateTime.utc_now() end}, params)
end
deffactory tag(params \\ %{}), struct: Tag do
base_params = %{name: FactoryMan.sequence("tag")}
Map.merge(base_params, params)
end
# Associations: each builder runs before the body and is the key's default
deffactory post(params \\ %{}),
struct: Post,
assocs: [
author: &build_user_struct/1,
tags: {&build_tag_struct/1, default: [%{name: "elixir"}, %{name: "testing"}]}
] do
base_params = %{title: "Post by #{params.author.username}"}
Map.merge(base_params, params)
end
# Struct-less factories: Only generates `build_*` and `build_*_list` functions
deffactory api_payload(params \\ %{}) do
base_params = %{action: "create", resource: "user"}
Map.merge(base_params, params)
end
end

The assocs: builders resolve each association before the body runs, so the body sees a built author, and callers can supply nested params, existing structs, or nil instead. See the Cookbook for chaining, variants, and recursion.

Each factory generates a family of functions.

iex> alias MyApp.Factory, as: Factory
MyApp.Factory
# Build a struct without saving it
iex> Factory.build_user_struct(%{username: "alice"})
%User{id: nil, username: "alice", ...}
# Build associations from nested params
iex> Factory.build_post_struct(%{author: %{username: "alice"}, tags: [%{name: "elixir"}]})
%Post{author: %User{username: "alice", ...}, tags: [%Tag{name: "elixir"}], ...}
# Atom-keyed input for a changeset
iex> Factory.build_user_params(%{username: "alice"})
%{username: "alice", ...}
# Build and save a struct
iex> Factory.insert_user(%{username: "alice"})
%User{id: 1, username: "alice", ...}
# Build and insert several, each built independently
iex> Factory.insert_user_list(3)
[%User{id: 2, ...}, %User{id: 3, ...}, %User{id: 4, ...}]
# Build a variant struct
iex> Factory.build_admin_user_struct(%{username: "the_boss"})
%User{id: nil, role: "admin", username: "the_boss", ...}
# Combine variants in one build
iex> Factory.build_user_struct(%{}, variants: [:admin, :confirmed])
%User{id: nil, role: "admin", confirmed_at: ~U[2026-09-24 12:00:00.000000Z], ...}
# Build a struct-less factory item
iex> Factory.build_api_payload()
%{action: "create", resource: "user"}

How It Works

You write one factory, and FactoryMan generates the rest:

Factories without a struct: option are simpler: they generate build_<name> and build_<name>_list, and the body can return any value (maps, keyword lists, strings, ...).

Organizing Factories

Keep shared configuration in a base factory:

defmodule MyApp.Factory do
use FactoryMan,
repo: MyApp.Repo,
strict: true,
hooks: [after_insert: &__MODULE__.reset_assocs/1]
def reset_assocs(struct) do
Ecto.reset_fields(struct, struct.__struct__.__schema__(:associations))
end
end

Child modules inherit its options and helper functions with use FactoryMan, extends: MyApp.Factory. See "Organize a growing factory suite" in the Cookbook for a recommended layout.

Going Further

The full reference lives in the FactoryMan module documentation, including: