Forgery v0.1.0 Forgery behaviour View Source

Forgery is a slim though extensible test data generator in Elixir.

Forgery provides a few simple APIs to work with. To get started, you need to implement the make/2 callback:

defmodule MyUser do
  defstruct [:id, :username, :password]
end

defmodule MyFactory do
  use Forgery

  def make(:user, fields) do
    fields
    |> put_new_field(:id, make_unique_integer())
    |> put_new_field(:username, "user" <> to_string(make_unique_integer()))
    |> create_struct(MyUser)
  end
end

iex> import MyFactory
iex>
iex> %MyUser{} = make(:user)
iex> %MyUser{id: 42} = make(:user, id: 42)
iex> [%MyUser{}, %MyUser{}] = make_many(:user, 2)

And just as simple as that!

Ecto integration

Forgery was built with easy Ecto integration in mind, though not limiting to it.

For example if you use Ecto and have MyRepo. You can add a function, says insert!, into the factory:

defmodule MyFactory do
  def insert!(factory, fields \ %{}) do
    :user
    |> make(fields)
    |> MyRepo.insert!()
  end

  def insert_many!(factory, amount, fields \ %{}) when amount >= 1 do
    [%schema{} | _] = entities = make_many(:user, amount, fields)

    {_, persisted_entities} = MyRepo.insert_all(schema, entities, returning: true)

    persisted_entities
  end
end

user = insert!(:user)
users = insert_many!(:user, 10, %{password: "1234567890"})

Link to this section Summary

Functions

Create struct of module from fields.

Returns monotonically increasing unique integer. It would be useful when it comes to generate unique serial IDs.

Lazily evaluate and put lazy_value into name if name does not exist in fields.

Callbacks

Makes data from the given factory.

Make multiple data from the given factory.

Link to this section Types

Link to this type

factory()

View Source
factory() :: atom()

Link to this section Functions

Link to this function

create_struct(fields, module)

View Source
create_struct(fields :: Enumerable.t(), module :: atom()) :: struct()

Create struct of module from fields.

iex> import Forgery
iex>
iex> create_struct(%{id: 1, username: "john", password: "123456"}, MyUser)
%MyUser{id: 1, password: "123456", username: "john"}
Link to this function

make_unique_integer()

View Source
make_unique_integer() :: pos_integer()

Returns monotonically increasing unique integer. It would be useful when it comes to generate unique serial IDs.

Link to this macro

put_new_field(fields, name, lazy_value)

View Source (macro)
put_new_field(fields :: Enumerable.t(), name :: any(), lazy_value :: any()) ::
  map()

Lazily evaluate and put lazy_value into name if name does not exist in fields.

iex> import Forgery
iex>
iex> fields = %{foo: 1}
iex> put_new_field(fields, :foo, 100 + 2)
%{foo: 1}
iex> put_new_field(fields, :bar, 100)
%{foo: 1, bar: 100}

Note that lazy_value is only evaluated when it is needed. For instance, in the following example, make_foo.() will not be invoked.

iex> import Forgery
iex>
iex> make_foo = fn -> raise("I am invoked") end
iex> fields = %{foo: 1}
iex> put_new_field(fields, :foo, make_foo.())
%{foo: 1}

Link to this section Callbacks

Link to this callback

make(factory, fields)

View Source
make(factory :: factory(), fields :: Enumerable.t()) :: any()

Makes data from the given factory.

The implementation of this callback should take in the factory name, as well and fields.

Link to this callback

make_many(factory, amount, fields)

View Source
make_many(factory :: factory(), amount :: integer(), fields :: Enumerable.t()) ::
  [any()]

Make multiple data from the given factory.

This function is roughly equivalent to:

Enum.map(1..amount, fn _ -> make(factory) end)

Example

make_many(:users, 3)
[
  %MyUser{id: 3, password: nil, username: "user3"},
  %MyUser{id: 5, password: nil, username: "user4"},
  %MyUser{id: 7, password: nil, username: "user5"},
]