ExMachina

Test factory library for Elixir — creates test data using factory definitions. ExMachina features: ExMachina.Ecto strategy for Ecto-backed factories, build/2 for in-memory structs, insert/2 for DB-persisted records, build_pair/insert_pair for 2 records, build_list/insert_list for N records, factory inheritance with map_merge, sequences for unique values (sequence(:email, &'user-#{&1}@example.com')), traits for variations, and custom strategies. Works with Ecto.Repo for database insertion. Elixir equivalent of FactoryBot (Ruby) for agent test data setup.

Evaluated Mar 06, 2026 (0d ago) v2.x
Homepage ↗ Repo ↗ Developer Tools elixir ex-machina factory testing fixtures ecto thoughtbot
⚙ Agent Friendliness
67
/ 100
Can an agent use this?
🔒 Security
93
/ 100
Is it safe for agents?
⚡ Reliability
86
/ 100
Does it work consistently?

Score Breakdown

⚙ Agent Friendliness

MCP Quality
--
Documentation
85
Error Messages
82
Auth Simplicity
98
Rate Limits
98

🔒 Security

TLS Enforcement
95
Auth Strength
95
Scope Granularity
92
Dep. Hygiene
88
Secret Handling
92

Test-only library — no network access. Factory files may define test passwords or tokens — use non-realistic placeholders, never real credentials. Ensure factory files are in test/ directory and not compiled into production release.

⚡ Reliability

Uptime/SLA
85
Version Stability
88
Breaking Changes
85
Error Recovery
88
AF Security Reliability

Best When

Your Elixir/Phoenix agent app uses Ecto and needs clean, composable test data factories — ExMachina is the standard Elixir factory library for creating test agent records with defaults, associations, and traits.

Avoid When

You're using a non-Ecto data layer, need production seeding, or prefer plain Repo.insert! for test setup.

Use Cases

  • Agent test data creation — insert(:agent, name: 'SearchAgent', status: :idle) creates persisted Agent with defaults; factory defined with build(:agent) returns %Agent{} struct; agent test setup creates realistic data without manual Repo.insert!
  • Agent with associations — insert(:agent_task, agent: insert(:agent), status: :running) creates task with associated agent in one line; ExMachina handles Ecto association IDs automatically; agent relationship tests use factory composition
  • Unique email sequences — sequence(:email, &'agent-#{&1}@example.com') generates unique emails per factory call; agent tests creating multiple users avoid unique constraint violations; sequences reset between test runs
  • Agent factory traits — build(:agent, :with_completed_tasks) where trait map_merges completed tasks; agent test scenarios (new agent, active agent, failed agent) defined as factory traits; tests use trait names not repetitive attribute overrides
  • In-memory agent testing — build(:agent, name: 'TestAgent') returns %Agent{} without DB insert; agent unit tests not requiring persistence get struct without DB round-trip; faster tests for agent logic not touching database

Not For

  • Non-Ecto data — ExMachina.Ecto requires Ecto.Repo; for Phoenix without Ecto use base ExMachina without Ecto strategy
  • Complex state machine factories — ExMachina doesn't sequence state transitions; for complex agent lifecycle factories build each state manually
  • Production data seeding — ExMachina is for tests; for seeds use Repo.insert! directly or priv/repo/seeds.exs

Interface

REST API
No
GraphQL
No
gRPC
No
MCP Server
No
SDK
Yes
Webhooks
No

Authentication

Methods: none
OAuth: No Scopes: No

No auth — test library that interacts with Ecto.Repo directly.

Pricing

Model: open_source
Free tier: Yes
Requires CC: No

ExMachina is MIT licensed, maintained by thoughtbot. Free for all use.

Agent Metadata

Pagination
none
Idempotent
Full
Retry Guidance
Not documented

Known Gotchas

  • use ExMachina.Ecto with repo: option required — defmodule MyApp.Factory, do: use ExMachina.Ecto, repo: MyApp.Repo; omitting repo: causes 'undefined function insert/2' error; agent factory modules must specify Repo or insertion won't work
  • build/2 vs insert/2 confusion — build creates in-memory struct (no DB); insert creates DB record; agent tests that call build then use the struct's ID in queries get nil id (no DB record); use insert for DB-backed agent test data
  • Factory associations must be built correctly — %{agent: build(:agent)} in factory creates non-persisted association; insert(:task, agent: build(:agent)) inserts task with non-persisted agent (no agent_id); use insert(:task, agent: insert(:agent)) for proper FK relationship in agent test data
  • sequences are global per factory module — sequence(:email, ...) increments globally across all tests in test run; agent tests relying on specific email format get different numbers each run; design agent factories to not depend on sequence value, only on uniqueness
  • traits must be atoms not strings — insert(:agent, :active) passes :active trait; insert(:agent, 'active') raises FunctionClauseError; agent test code using string trait names from non-Elixir background causes confusing errors; traits are always atoms
  • ExMachina.Ecto insert! doesn't respect Ecto sandbox isolation by default — Ecto sandbox with :shared mode requires Ecto.Adapters.SQL.Sandbox.allow(MyApp.Repo, test_pid, factory_pid) when factories run in separate processes; agent test factories called from concurrent ExUnit tests need sandbox ownership

Alternatives

Full Evaluation Report

Detailed scoring breakdown, competitive positioning, security analysis, and improvement recommendations for ExMachina.

$99

Scores are editorial opinions as of 2026-03-06.

5229
Packages Evaluated
26151
Need Evaluation
173
Need Re-evaluation
Community Powered