FactoryMan (Factory Man v0.12.0)
View SourceAn Elixir library for generating test data. Define factories with deffactory, and FactoryMan
generates functions for building params and structs, and inserting database records.
Quick Start
defmodule MyApp.Factory 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
endGenerated Functions
For a factory named :user with struct: User and a plain params argument that defaults to an empty
map, the following functions are available. Insert functions require a configured repo, a table-backed
Ecto schema, and insert? not set to false.
| Function | Returns | Purpose |
|---|---|---|
build_user_struct/0,1 | %User{} | Struct in memory (not persisted) |
build_user_params/0,1 | %{} | Clean params map derived from struct |
build_user_string_params/0,1 | %{"" => ...} | Same, with string keys |
insert_user/0,1,2 | %User{} | Inserted into database |
build_user_struct_list/1,2 | [%User{}, ...] | List of structs |
build_user_params_list/1,2 | [%{}, ...] | List of params maps |
build_user_string_params_list/1,2 | [%{}, ...] | List of string-keyed params maps |
insert_user_list/1,2,3 | [%User{}, ...] | List of inserted records |
insert_user_struct/1,2 | %User{} | Inserts an already-built struct |
Builders and insert_user accept factory params. insert_user_struct takes an existing %User{}
instead. Insert functions also accept repo options. Each list item is built independently.
Zero-arity builders and inserts require a default argument in the factory head. For struct
factories, count-only list functions pass %{} and are omitted when the head pattern-matches its
argument. Non-struct count-only list functions require a default argument and use that default.
What gets generated depends on the factory configuration:
| Factory configuration | Value builders | Params builders | Struct builders | Inserts |
|---|---|---|---|---|
No struct: option | Yes | No | No | No |
| Plain struct | No | Yes | Yes | No |
| Table-backed Ecto schema | No | Yes | Yes | Yes, when enabled |
| Embedded schema | No | Yes | Yes | No |
Value builders use build_<name> and build_<name>_list. Params builders include atom-keyed and
string-keyed functions. Inserts require a configured repo and insert? not set to false. Setting
body: :struct changes how the struct is built, not which function families are generated.
The diagram shows the build pipeline with body: :params. Configured :associations are
normalized after before_build_params and before the factory body. Each function shown has a
list counterpart that builds every item independently. insert_user_struct, not shown, starts at the
insert pipeline and has no list counterpart:
flowchart TD
body["factory body<br/>(returns params map)"]
struct_fn["build_user_struct/0,1<br/>params hooks → lazy eval → struct!/2 → struct hooks"]
params_fn["build_user_params/0,1<br/>struct stripped to a clean map"]
string_params_fn["build_user_string_params/0,1<br/>keys converted to strings"]
insert_fn["insert_user/0,1,2<br/>insert hooks → Repo.insert!/2"]
body --> struct_fn
struct_fn --> params_fn
params_fn --> string_params_fn
struct_fn --> insert_fnDefining Factories
The deffactory macro defines a named factory with one argument and a body. With struct: and
the default body: :params, return a plain map containing only fields of that struct. With
body: :struct, return the struct directly. Without struct:, the body can return any value.
deffactory user(params \\ %{}), struct: User do
base_params = %{username: "user-#{System.os_time()}"}
Map.merge(base_params, params)
endYou can name the parameter anything, and use pattern matching:
deffactory user_from_config(%{username: username} = params), struct: User do
base_params = %{username: username}
Map.merge(base_params, params)
endStruct vs. Non-Struct Factories
The struct: option controls both what functions are generated and how they're named:
# Struct factory — generates build_user_params, build_user_struct, insert_user, etc.
deffactory user(params \\ %{}), struct: User do
base_params = %{username: "user-#{System.os_time()}"}
Map.merge(base_params, params)
end
# Non-struct factory — generates build_api_payload and build_api_payload_list only
deffactory api_payload(params \\ %{}) do
%{action: "create", data: params}
end| Factory type | Generated functions |
|---|---|
struct: User (:user) | build_user_params, build_user_struct, insert_user, etc. |
No struct: (:api_payload) | build_api_payload, build_api_payload_list |
Non-struct factories use simplified names (build_* instead of build_*_params) because
they can return any value — maps, strings, keyword lists, tuples, nil, etc.:
deffactory greeting(name \\ "world") do
"Hello, #{name}!"
end
deffactory search_opts(overrides \\ []) do
Keyword.merge([page: 1, per_page: 20], overrides)
endLazy evaluation works in keyword lists the same way it does in maps — 0-arity and 1-arity functions are resolved at build time. Non-map, non-keyword-list values are passed through unchanged.
Associations — configure nested params with the :associations option (see the
Cookbook):
deffactory author(params \\ %{}), struct: Author, associations: [user: :user] do
base_params = %{
name: "Test Author",
user: build_user_struct()
}
Map.merge(base_params, params)
endThe association key is resolved only when supplied by the caller. A nested params map becomes
the associated struct, while an existing struct is reused. Missing keys continue to use the
factory's ordinary base_params defaults.
Association targets are factory names, not schema names:
associations: [user: :user]references a factory registered in the current module.associations: [user: {MyApp.AccountFactory, :user}]references another factory module.- Registered variants can be targets using their full registered names.
Ecto supplies the related schema and cardinality. Factory references are checked at runtime, including when the caller omits an association key. A same-module target may therefore be declared later in the module. The atom shorthand does not search imported or ancestor modules; use an explicit module tuple for those factories.
| Caller value | Singular association | Plural association |
|---|---|---|
| Key absent | Leave absent; body defaults apply | Leave absent; body defaults apply |
| Params map | Build through the configured factory | Raise |
| Correct struct | Reuse unchanged | Raise; supply a list |
nil | Preserve nil | Raise; use [] |
| List of maps/structs | Raise | Resolve each member in order |
Wrong struct types, invalid list members, and incorrectly typed builder results raise. Only configured keys are normalized. Direct Ecto associations are supported; embeds and through associations are not. Normalization calls struct builders, not insert functions.
Factory defaults remain ordinary Elixir expressions: eager default builders run even when overridden. Use existing lazy attributes when a default should only be built if retained. FactoryMan does not automatically build omitted relationships or prevent recursion caused by mutually recursive default builders.
Params Functions
For struct factories, build_*_params and build_*_string_params build the struct and
convert it to a clean map suitable for changesets or controller tests. For Ecto schemas, all
Ecto metadata is stripped; for plain structs, the struct is converted with Map.from_struct/1:
# Returns %{username: "alice", first_name: nil, ...}
# (no __struct__, __meta__, autogenerated :id, or NotLoaded associations)
build_user_params(%{username: "alice"})
# Same but with string keys: %{"username" => "alice", ...}
build_user_string_params(%{username: "alice"})belongs_to associations are removed from the output. If the association is persisted, its
foreign key is set instead. Ordinary fields retain nil values, but nil embeds are omitted. Struct
values such as DateTime are left untouched.
Factory Options
Options cascade: parent module -> child module -> individual factory.
Module-level (set with use FactoryMan):
:repo— Ecto repo for database operations:extends— Parent factory module to inherit configuration from:hooks— Hooks applied to all factories in the module
Factory-level (set with deffactory):
:struct— Ecto schema module (enables struct, params, and insert functions):insert?— Set tofalseto skip insert functions:body— What the factory body returns::params(default, a params map) or:struct(a struct built directly by the body). Params functions are generated either way (derived from the struct). Ignored for non-struct factories.:hooks— Merged with module-level hooks:associations— Keyword list mapping Ecto association keys to FactoryMan factories. Use an atom for a same-module factory or{FactoryModule, :factory}across modules. Ecto supplies the associated schema and cardinality; caller-provided nested params are normalized before the factory body runs.:strict— Reject unknown param keys at the factory boundary (see Strict Params below)
Options that only apply to struct factories (:body, :associations, :strict) cascade
from the module level. :body and :strict are ignored by non-struct factories; non-empty
:associations requires an Ecto-backed struct factory.
Strict Params
Factories can silently ignore misspelled param keys: merge-style bodies surface the typo late
(in struct!/2, with an unhelpful message), and body: :struct bodies — which read params
selectively — never surface it at all. Opt in to strict: true to reject unknown keys up
front:
deffactory user(params \\ %{}), struct: User, strict: true do
base_params = %{username: FactoryMan.sequence("user")}
Map.merge(base_params, params)
end
build_user_struct(%{usernme: "typo"})
# ** (ArgumentError) unknown params [:usernme] for strict factory :user ...The check runs when building starts — before hooks and the factory body — against the keys of
the :struct option's struct (which includes virtual fields and association keys). All derived
functions (params builders, inserts, lists, and variants of the factory) are covered.
When a factory intentionally accepts keys that are not struct fields (e.g. an input used only to derive other fields), allow them explicitly:
deffactory invoice(params \\ %{}), struct: Invoice, strict: [allow: [:line_item_count]],
body: :struct do
%Invoice{total: Map.get(params, :line_item_count, 1) * 100}
endLike other options, :strict can be set module-wide with use FactoryMan, strict: true and
overridden per-factory (e.g. strict: false). Non-struct factories have no reference field
set, so the option is ignored for them.
Hooks
Transform data at specific stages. Every factory action has both a before and after hook.
Hook Pipeline
Each generated function uses a subset of the pipeline. The full flow for insert_user is:
build_user_struct:
strict validation → before_build_params → configured association normalization
→ [factory body + lazy eval] → after_build_params
→ before_build_struct → struct!() → after_build_struct
build_user_params (calls build_user_struct internally):
→ strip Ecto metadata (or Map.from_struct/1 for plain structs)
insert_user (calls build_user_struct internally):
→ before_insert → Repo.insert!() → after_insertWith body: :struct, configured associations are normalized after strict validation and before
the body. Params-stage hooks remain skipped. Variants preprocess input before delegating to the
base builder, which performs normalization. insert_*_struct receives an already-built struct
and does not run association normalization.
For non-struct factories, build_* runs before_build_params, the factory body with lazy
evaluation, then after_build_params.
insert_user_struct/1,2 runs the same before_insert → insert → after_insert pipeline on
an already-built struct — use it after modifying a built struct, so records are shaped
consistently no matter how they were constructed. A raw Repo.insert!/2 would skip the
insert hooks.
Hook Reference
| Hook | Receives | Returns | When to Use |
|---|---|---|---|
:before_build_params | params (map) | params (map) | Transform or inject params before the factory body runs |
:after_build_params | params (map) | params (map) | Modify params after the factory body (e.g. add computed fields) |
:before_build_struct | params (map) | params (map) | Last chance to modify params before struct!() is called |
:after_build_struct | struct | struct | Transform the struct after creation (e.g. set virtual fields) |
:before_insert | struct | struct | Modify struct just before database insertion |
:after_insert | struct | struct | Post-process after insertion (e.g. reset associations) |
Hook Precedence
Hooks can be set at three levels. Later levels override earlier ones for the same hook key:
- Parent module —
use FactoryMan, hooks: [...] - Child module —
use FactoryMan, extends: Parent, hooks: [...] - Individual factory —
deffactory name(params), hooks: [...]
Examples
Reset associations after insert:
defmodule MyApp.Factory do
use FactoryMan,
repo: MyApp.Repo,
hooks: [after_insert: &__MODULE__.reset_assocs/1]
def reset_assocs(struct) do
Ecto.reset_fields(struct, struct.__struct__.__schema__(:associations))
end
endLog factory usage for debugging:
deffactory user(params \\ %{}), struct: User,
hooks: [after_build_params: &__MODULE__.log_params/1] do
base_params = %{username: "user-#{System.os_time()}"}
Map.merge(base_params, params)
end
def log_params(params) do
IO.inspect(params, label: "factory params")
params
endFactory Inheritance
Child factories inherit the parent's repo, hooks, and helper functions via :extends:
defmodule MyApp.Factory do
use FactoryMan, repo: MyApp.Repo
def generate_username, do: "user-#{System.os_time()}"
end
defmodule MyApp.Factory.Accounts do
use FactoryMan, extends: MyApp.Factory
deffactory user(params \\ %{}), struct: User do
base_params = %{username: generate_username()}
Map.merge(base_params, params)
end
endInheritance chains are unlimited — a child factory can itself be extended.
Variant Factories (defvariant)
A variant wraps an existing base factory. It transforms the caller's params before passing them to the base factory. Think of it as a preprocessor: the variant runs first, then the base factory runs with the transformed params.
This ordering can be counterintuitive because the variant is defined after the base factory in your code, but its logic executes before the base factory at runtime:
Code order: deffactory user(...) -> defvariant admin(...), for: :user
Execution order: admin (preprocessor) -> user (base factory)Example
deffactory user(params \\ %{}), struct: User do
base_params = %{username: FactoryMan.sequence("user"), role: "member"}
Map.merge(base_params, params)
end
defvariant admin(params \\ %{}), for: :user do
base_params = %{role: "admin"}
Map.merge(base_params, params)
endCalling build_admin_user_struct() is equivalent to build_user_struct(%{role: "admin"}).
Calling build_admin_user_struct(%{role: "superadmin"}) passes %{role: "superadmin"} to
the base factory because the caller's params override the variant defaults.
Generated functions follow the pattern {variant}_{base}:
build_admin_user_params/0,1, build_admin_user_struct/0,1, insert_admin_user/0,1,2,
plus list variants.
Custom naming with :as
The :as option overrides the combined {variant}_{base} name:
defvariant moderator(params \\ %{}), for: :user, as: :mod do
base_params = %{role: "moderator"}
Map.merge(base_params, params)
endThis generates build_mod_struct/0,1, insert_mod/0,1,2, etc.
— instead of the default build_moderator_user_struct.
Sequences
Generate sequential values or cycle through a list:
FactoryMan.sequence("user") # "user0", "user1", ...
FactoryMan.sequence(:email, fn n -> "user#{n}@example.com" end) # custom formatter
FactoryMan.sequence(:role, ["admin", "moderator", "user"]) # cycles through list
FactoryMan.sequence(:order, fn n -> "ORD-#{n}" end, start_at: 1000) # custom start valueReset in test setup: FactoryMan.Sequence.reset()
Lazy Evaluation
Functions in factory params are evaluated at build time. This works in both maps and keyword lists:
# In maps
%{
created_at: fn -> DateTime.utc_now() end, # 0-arity: called with no args
display_name: fn user -> "#{user.username} (User)" end # 1-arity: receives parent map
}
# In keyword lists
[
created_at: fn -> DateTime.utc_now() end,
label: fn kw -> "timeout-#{kw[:timeout]}" end # 1-arity: receives parent keyword list
]Lazy evaluation ordering
1-arity functions receive the map or keyword list before lazy evaluation. Don't reference other lazy fields — they'll still be function references, not resolved values.
Embedded Schemas
Factories for embedded schemas work like regular struct factories but without database insertion:
defmodule MyApp.Factories.Settings do
use FactoryMan, extends: MyApp.Factory
alias MyApp.Users.Settings
deffactory settings(params \\ %{}), struct: Settings do
base_params = %{
theme: "dark",
notifications: true
}
Map.merge(base_params, params)
end
endEmbedded schemas generate build_*_struct, build_*_params, and build_*_string_params, plus
their matching *_list functions. They do not generate insert functions.
Direct Struct Factories (body: :struct)
For complex factories that need full control over struct construction, set body: :struct.
The factory body returns a struct directly instead of a params map:
deffactory invoice(params \\ %{}), struct: Invoice, body: :struct do
customer =
case params[:customer] do
%Customer{} = customer -> customer
_ -> MyApp.Factory.Accounts.insert_customer()
end
%Invoice{
customer: customer,
total: Map.get(params, :total, Enum.random(100..10_000))
}
endThis generates the full function family, including build_invoice_params (derived from the
built struct). The after_build_struct, before_insert, and after_insert hooks still run.
The before_build_params, after_build_params, and before_build_struct hooks are skipped
since there is no params-to-struct conversion stage.
body: :struct can also be set at the module level with use FactoryMan, body: :struct,
then overridden per-factory with body: :params if needed. Non-struct factories in the
same module are unaffected — their build_* functions are always generated.
Cookbook
A practical progression from a first factory through realistic defaults, variants, associations, suite organization, hooks, strict params, and advanced presets lives in the Cookbook guide.
Reflection and Debugging
Every factory module gets a __factory_man__/1,2 reflection function:
iex> MyApp.Factory.__factory_man__(:opts)
[repo: MyApp.Repo]
iex> MyApp.Factories.Users.__factory_man__(:opts, :user)
[repo: MyApp.Repo, struct: User]
iex> MyApp.Factories.Users.__factory_man__(:factories)
[:user, :admin_user]:factories lists every factory and variant registered in the module (variants under their
full name), which enables runtime dispatch without string-building function names:
def build_any(factory_module, factory_name, params) do
if factory_name not in factory_module.__factory_man__(:factories) do
raise ArgumentError, "unknown factory #{inspect(factory_name)}"
end
apply(factory_module, :"build_#{factory_name}_struct", [params])
end
Summary
Functions
Merge child factory options into parent options.
Validate params against a strict factory's allowed keys.
Resolve one association value.
Resolve a list of association values.
Defines a factory that generates test data.
Defines a variant factory that wraps a base factory.
Evaluate lazy attributes in a map, struct, or keyword list.
The default handler for hooks. This function is a no-op, and simply returns the given value
without any modifications.
Get the configured handler for a hook, or fall back to &FactoryMan.fallback_hook_handler/1.
Generates a sequence of strings.
Returns the next value in a named sequence.
Returns the next value in a named sequence using a formatter function.
Functions
Merge child factory options into parent options.
Most options are overridden per-key, but :hooks are merged per hook key so that a child
setting one hook does not discard the parent's other hooks.
This is a FactoryMan internal function — called from macro-generated code. Use the underscore prefix convention to signal that it is not part of the public API.
Validate params against a strict factory's allowed keys.
strict is the compile-time-parsed :strict option: false (disabled) or a list of extra
allowed keys. Allowed keys are the struct's keys plus the extras; any other key raises.
Non-map params are passed through (they fail downstream the same way they would without
strict checking).
This is a FactoryMan internal function — called from macro-generated code. Use the underscore prefix convention to signal that it is not part of the public API.
Resolve one association value.
A params map is passed to build_fun; an existing struct is reused without calling the builder;
and nil builds with the default %{} params, or :inherit when supplied. For ordinary Ecto
factory associations, prefer the :associations factory option.
This helper is useful when a caller accepts either an already-built struct or params for building one. It does not inspect or modify a containing factory params map.
build_fun is any 1-arity function that receives params for a new associated value.
Options
:struct— validate supplied structs and builder results against this module.:inherit— params merged below a supplied params map before building (default:%{}).:on_nil—:build(default) builds a nil value;:keeppreserves nil.
Examples
FactoryMan.assoc(%{name: "Ann"}, &build_author_struct/1)
FactoryMan.assoc(existing_author, &build_author_struct/1, struct: Author)
FactoryMan.assoc(nil, &build_author_struct/1, on_nil: :keep)
Resolve a list of association values.
nil and [] resolve to []. Each list item must be either a params map or an existing
struct. Params maps are passed to build_fun, while structs are reused without invoking it.
Mixed lists are supported and preserve their order. Nil elements inside a list are rejected.
Unlike the declarative :associations option, this low-level helper treats an outer nil
collection as an empty list.
Options
:struct— validate supplied structs and builder results against this module.:inherit— params merged below each supplied params map before building (default:%{}).
Examples
FactoryMan.assoc_list(
[%{body: "a"}, existing_comment],
&build_comment_struct/1,
struct: Comment
)
Defines a factory that generates test data.
The deffactory macro creates a set of functions for building test data. It works like
defining a function, where you specify the factory name and a parameter (typically params).
Options
:struct- The struct or Ecto schema module to build. When provided, generates struct, params, and insert functions.:insert?- Set tofalseto skip generating insert functions (default:truewhen repo is configured and struct is insertable):body- What the factory body returns::params(default, a params map) or:struct(a struct built directly by the body). Params functions are generated either way (derived from the struct). Ignored for non-struct factories.:hooks- A keyword list of hook functions to apply at different stages (see Hooks section):associations- A keyword list mapping Ecto association keys to FactoryMan factories. Use:userfor a factory in the current module or{FactoryModule, :user}for a cross-module factory. Ecto supplies the associated schema and cardinality; caller-provided nested params are normalized into associated structs before the body. Missing keys remain untouched sobase_paramscontinues to provide defaults. Direct associations are supported; embeds and:throughassociations are not.:strict- Set totrueto raise on param keys that are not fields of the:structoption's struct, or[allow: [...]]to permit specific extra keys (see the Strict Params section). Ignored for non-struct factories.
Generated Functions
For a factory named user with struct: User and a plain params argument that defaults to an
empty map, the following functions are generated. Insert functions require a configured repo, a table-backed
Ecto schema, and insert? not set to false.
build_user_struct/0,1- Returns an unsaved structbuild_user_params/0,1- Clean params map derived from the built structbuild_user_string_params/0,1- Same, with string keysinsert_user/0,1,2- Inserts into the database (when repo is configured)build_user_struct_list/1,2- Builds multiple structsbuild_user_params_list/1,2- Builds multiple params mapsbuild_user_string_params_list/1,2- Builds multiple string-keyed params mapsinsert_user_list/1,2,3- Inserts multiple items (when repo is configured)insert_user_struct/1,2- Inserts an already-built struct through the insert pipeline
For a factory named greeting without struct:, simplified names are used:
build_greeting/1- Returns the factory's valuebuild_greeting_list/2- Builds multiple items
With a default argument in the factory head, build_greeting/0 and build_greeting_list/1 are
also generated.
Examples
deffactory user(params \\ %{}), struct: User do
base_params = %{
username: FactoryMan.sequence("user"),
email: FactoryMan.sequence(:email, fn n -> "user#{n}@example.com" end)
}
Map.merge(base_params, params)
end
iex> MyApp.Factory.build_user_params(%{username: "alice"})
%{username: "alice", email: "user0@example.com", role: nil, ...}
iex> MyApp.Factory.insert_user(%{role: "admin"})
%User{id: 1, username: "user1", email: "user1@example.com", role: "admin"}
Defines a variant factory that wraps a base factory.
A variant is a preprocessor: it receives the caller's params, transforms them, and delegates to the base factory. The variant body runs before the base factory, not after.
Example
deffactory user(params \\ %{}), struct: User do
base_params = %{username: FactoryMan.sequence("user"), role: "member"}
Map.merge(base_params, params)
end
defvariant admin(params \\ %{}), for: :user do
base_params = %{role: "admin"}
Map.merge(base_params, params)
end
# Generated: build_admin_user_struct/0,1, insert_admin_user/0,1,2, etc.
# Calling build_admin_user_struct() is equivalent to:
# build_user_struct(%{role: "admin"})Options
:for- (atom, required) The name of the base factory to wrap (e.g.:user):as- Instead of the default<variant>_<base>structure used when generating factory functions, (e.g.build_admin_user_struct), you may specify a custom name to use when generating the factory functions (e.g.as: :admin->build_admin_struct)
Variants are registered under their full name, so a variant can itself serve as the base of
another variant (e.g. defvariant senior(params \\ %{}), for: :admin_user).
Evaluate lazy attributes in a map, struct, or keyword list.
Functions with 0 arity are called with no arguments. Functions with 1 arity receive the parent factory (map, struct, or keyword list) as their argument.
Non-map, non-keyword-list values are passed through unchanged.
Examples
iex> FactoryMan.evaluate_lazy_attributes(
...> %{name: "test", timestamp: fn -> System.os_time() end}
...> )
%{name: "test", timestamp: 12345}
iex> FactoryMan.evaluate_lazy_attributes(
...> %{first: "John", last: fn attrs -> attrs.first <> " Smith" end}
...> )
%{first: "John", last: "John Smith"}
iex> FactoryMan.evaluate_lazy_attributes(
...> [timeout: 5000, created_at: fn -> DateTime.utc_now() end]
...> )
[timeout: 5000, created_at: ~U[2026-01-01 00:00:00Z]]
iex> FactoryMan.evaluate_lazy_attributes("plain string")
"plain string"
The default handler for hooks. This function is a no-op, and simply returns the given value
without any modifications.
Examples
iex> FactoryMan.fallback_hook_handler(123)
123
Get the configured handler for a hook, or fall back to &FactoryMan.fallback_hook_handler/1.
Examples
iex> hooks = [after_insert: &YourProject.Factories.Users.user_after_insert_handler/1]
iex> FactoryMan.get_hook_handler(hooks, :before_build)
&FactoryMan.fallback_hook_handler/1
iex> FactoryMan.get_hook_handler(hooks, :after_insert)
&YourProject.Factories.Users.user_after_insert_handler/1
Generates a sequence of strings.
The sequence name is used as the beginning of the string. For example, if you
do FactoryMan.sequence("joe"), you will get back "joe0", then "joe1", and so on.
Example
def user_factory do
%{
username: FactoryMan.sequence("joe")
}
endIf you want to customize the returned string you can use sequence/2.
Returns the next value in a named sequence.
A formatter function receives the current counter. A list cycles through its items. Returned values are not guaranteed to be unique.
Example with a formatter function
def user_factory do
%{
email: FactoryMan.sequence(:email, fn n -> "me-#{n}@foo.com" end)
}
endExample with a list
def user_factory do
%{
name: FactoryMan.sequence(:name, ["Joe", "Mike", "Sarah"])
}
end
@spec sequence(any(), (integer() -> any()), [{:start_at, non_neg_integer()}]) :: any()
Returns the next value in a named sequence using a formatter function.
:start_at sets the initial counter when the named sequence does not yet exist. It does not change
an existing counter. List formatters are supported by sequence/2, not sequence/3.
Example
def money_factory do
%{
cents: FactoryMan.sequence(:cents, fn n -> "#{n}" end, start_at: 600)
}
end