README.md

# FactoryMan

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

## Installation

Add FactoryMan to your `mix.exs` dependencies:

```elixir
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:

```elixir
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:

```elixir
# 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:

```elixir
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:

```elixir
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

- **Simple factories** - Define factories with minimal boilerplate
- **Automatic struct building** - Define Ecto schemas and FactoryMan handles the rest
- **Database insertion** - Built-in `insert_` functions with configurable repo
- **List factories** - Create multiple records with `*_list` functions
- **Sequence generation** - Automatic unique value generation for usernames, emails, etc.
- **Lazy evaluation** - Compute values at build time with 0 or 1 arity functions
- **Factory composition** - Nest factories for complex associations
- **Optional inheritance** - Share config across modules with `:extends`
- **Hooks** - Transform data at build, insert, or any stage with custom hooks

## Documentation

Full documentation is available in the `FactoryMan` module:

- Basic factory creation and usage
- List factories for bulk data creation
- Sequence generation for unique values
- Lazy evaluation for computed attributes
- Factory inheritance with the `:extends` option
- Hooks for custom transformation logic