fuelen

fuelen

SeedFactory - a toolkit for test data generation

SeedFactory - a toolkit for test data generation

GitHub | docs | Hex.pm

The main idea of SeedFactory is to generate test data by calling your application’s business logic (context functions if you use Phoenix Contexts) instead of inserting directly into the database. This means your tests work with data that was created the same way it would be in production. SeedFactory resolves dependencies automatically, so you don’t need to worry about the details of preparing data that your test doesn’t directly care about.

Even in cases where calling business logic functions is impractical (e.g. for performance reasons), SeedFactory serves as a centralized hub for test data creation, ensuring a consistent approach across your test suite.

The library is completely agnostic to the database toolkit.

See the Overview section on GitHub and docs for details.

Feel free to ask any questions!

Most Liked

hauleth

hauleth

That seems like super reasonable approach to factories. I already like that, however it feels a little bit macro heavy.

fuelen

fuelen

Actually, command resolver can use whatever code you need. So, you can use something that differs from the actual implementation, like a simplified version of it. But the fact that it is placed in a single centralized place makes it very maintainable.

When I read your comment for the first time, I was surprised why do you think so, as there is only 1 macro – produce/1. Completely forgot that DSL for schema definition is built on macros :smile: That’s because the heavy lifting is done by spark (@zachdaniel thank you for the library, support and quick bug fixing!)

I tried to describe the schema using simple structures in my initial implementation. But eventually, current implementation won.

fuelen

fuelen

SeedFactory v0.7.0 Released :tada:

A big release with many internal changes

Same trait from multiple commands

The same trait can now be defined with different commands. This enables schemas that mirror real business logic where the same state can be reached through different paths:

command :create_user do
  # ... creates user with status: :pending
  produce :user
end

command :activate_user do
  param :user, entity: :user, with_traits: [:pending]
  # ... updates user to status: :active
  update :user
end

command :create_active_user do
  # ... creates user with status: :active directly
  produce :user
end

# :active can be reached via transition...
trait :active, :user do
  from :pending
  exec :activate_user
end

# ...or directly
trait :active, :user do
  exec :create_active_user
end

# Unique marker for the direct path
trait :pending_skipped, :user do
  exec :create_active_user
end

Usage:

# SeedFactory picks the first declared command by default
produce(ctx, user: [:active])

# Force a specific path using a trait unique to that command
produce(ctx, user: [:active, :pending_skipped])

When multiple commands can produce the same trait, SeedFactory automatically picks one based on which commands can satisfy their dependencies without duplicating existing entities.

Compile-time validations

Schemas are now validated more thoroughly at compile time with helpful “did you mean?” suggestions in error messages.

Documentation

README now includes an “Advanced features” section covering pre_exec/pre_produce, args_match/generate_args, and trail tracking.

Last Post!

fuelen

fuelen

SeedFactory v0.8.0 Released!

This release is focused on developer experience: better error reporting, improved documentation, and fewer dependencies.

Structured error reporting

When a command fails, you now get SeedFactory.ExecError with a visual execution plan showing what succeeded, what failed, and what was still pending:

** (SeedFactory.ExecError) unable to execute :create_user command: :email_already_taken

Execution plan:
  ✔ :create_company
  ✔ :create_office
  ✖ :create_user
  · :activate_user
  · :create_profile

Current traits:
  %{company: [], office: [:main]}

Execution history

Every produce/exec call is now recorded in meta, providing a full audit trail of how a context was built. Combined with a compact inspect format, it’s easy to see what happened:

#execution[produce(user: [:admin, :active]): create_company → create_user → activate_user]
#execution[produce(order: [:pending]): create_order]

Performance

Replaced libgraph dependency with an inline topological sort, optimized compile-time trait indexing, and fixed quadratic list accumulation — fewer dependencies and faster compilation.

Where Next?

Popular in Announcing Top

KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36654 110
New
mischov
import Meeseeks.CSS html = HTTPoison.get!("https://news.ycombinator.com/").body for story <- Meeseeks.all(html, css("tr.athing")) do...
New
treble37
Just looking for a little feedback on a tiny helper library I built - Sometimes I find the need to convert maps with atom keys to maps w...
New
josevalim
EDIT: since Ecto 3.0 final version is out, this post was amended to use the final versions in the instructions below. Hi everyone, We a...
New
tmbb
I’ve been working on two packages (not on hex.pm yet) to build admin interfaces for phoenix apps: bureaucrat - which contains a bunch ...
New
kevinlang
Hey all, We have made an Ecto3 Adapter for SQLite3, ecto_sqlite3! We have successfully on-boarded the full suite of integration tests (...
New
zachdaniel
Ash Framework What is Ash? Ash Framework is a declarative, resource-oriented application development framework for Elixir. A resource can...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 130286 1222
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 54006 488
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New

We're in Beta

About us Mission Statement