README.md

# Refactory

An Elixir library to generate test data recursively with traits

## Installation

The package can be installed
by adding `refactory` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:refactory, "~> 0.1.0", only: :test}
  ]
end
```

Documentation can found at <https://hexdocs.pm/refactory/>.

<!-- MODULEDOC -->
Refactory allows generating Ecto records with nested overrides for your tests.

## Factory module

To start using Refactory, first define a factory module:

```
defmodule MyApp.Factory do
  use Refactory, repo: MyApp.Repo
end
```

## Usage

The factory module has two functions:

- `build/2` generates an Ecto record with the given traits applied
- `create/2` inserts an Ecto record into the database

## Traits

A trait can be
- a `Map` in which each key-value pair is either
  - a field with its value
  - an association with a trait (for `belongs_to`, `has_one`, and `embeds_one`)
  - _soon:_ an association with a list of traits (for `has_many` and `embeds_many`)
- a custom trait defined in the factory module (see below)
- a `Tuple` with multiple traits to be applied

## Basic example

```
defmodule MyApp.Factory do
  use Refactory, repo: MyApp.Repo
end

MyApp.Factory.build(MyApp.List, %{
  title: "Refined List",
  created_by_user: %{email: "test@email.org"}
})

%MyApp.List{
  title: "Refined List",
  created_by_user: %MyApp.User{
    email: "test@email.org"
  }
}
```

## Default traits

Default traits can be defined in the factory module.
They are always applied first.

```
defmodule MyApp.Factory do
  use Refactory, repo: MyApp.Repo

  def trait(MyApp.List, :default) do
    %{
      title: "Default Title"
    }
  end
end


MyApp.Factory.build(MyApp.List)

%MyApp.List{title: "Default Title"}
```

## Custom traits

Custom traits can be defined in the factory module and then used by their name.

```
defmodule MyApp.Factory do
  use Refactory, repo: MyApp.Repo

  def trait(MyApp.List, :default) do
    %{
      title: "Default Title"
    }
  end

  def trait(MyApp.List, :with_admin_user) do
    %{
      created_by_user: %{
        role: :admin
      }
    }
  end
end


MyApp.Factory.build(MyApp.List, :with_admin_user)

%MyApp.List{title: "Default Title", created_by_user: %MyApp.User{role: :admin}}
```
<!-- MODULEDOC -->

## Why another factory library?

To my knowledge, this is the only factory library that supports recursive traits,
providing a powerful declarative appraoch to (test) data generation.

Recursive and/or nested approaches might be tricky in non-functional programming
languages, because the resulting objects often encapsulate internal state.
In Elixir, however, data structures are cleanly separated from behavior,
making it a great field of application for recursive data structure generation.

## Special thanks

This project is sponsored and kindly supported by [Team Engine](https://www.teamengine.co.uk/).

If you'd like to join us working on [Dx](https://github.com/elixir-dx/dx) and Refactory
as a contractor, please reach out to [@arnodirlam](https://github.com/arnodirlam).