ExZample v0.10.1 ExZample behaviour View Source

ExZample is a factory library based on Elixir behaviours.

Link to this section Summary

Functions

Builds a struct with given factory_or_alias module.

Same as build/2, but returns a list with where the size is the given count.

Same as build/2, but returns a tuple with a pair of structs.

Creates aliases for your factories to simplify the build calls.

Same as config_aliases/1, but you can define a different scope.

Creates a sequence with the given name.

Same as create_sequence/1, but you can define a different scope or a sequence function.

Same as create_sequence/1, but you can define a different scope and a sequence function.

Utiliy function that you can define severial settings that ExZample will look for before executing their functions.

Inserts in the repository the example built by the factory_or_alias module.

Same as insert/2, but the attributes and opts are explicit separated.

Same as insert/2, but returns a list with where the size is the given count.

Same as insert/3, but returns a list with where the size is the given count.

Same as insert/2, but returns a tuple with a pair of structs.

Same as insert/3, but returns a tuple with a pair of structs.

Builds a map with given factory_or_alias module. Has the same mechanism of build/2.

Same as map_for/2, but returns a list with where the size is the given count.

Same as map_for/2, but returns a tuple with a pair of maps.

Builds a map with string keys given factory_or_alias module. Has the same mechanism of build/2. Useful to simulate request parameters in a plug or phoenix controller.

Same as params_for/2, but returns a list with where the size is the given count.

Same as params_for/2, but returns a tuple with a pair of maps.

Returns the current counter registered in the given sequence name.

Same as sequence/1, but returns a list of where the number is determined by the given count.

Same as sequence/1, but returns a pair of sequence items.

Callbacks

Invoked every time you insert your data using ExZample module.

Invoked every time you build your data using ExZample module.

Same as example/0, but here you have the full control in how will build your struct given the attributes.

Link to this section Types

Link to this type

sequence_fun()

View Source
sequence_fun() :: (pos_integer() -> term())

Link to this section Functions

Link to this function

build(factory_or_alias, attrs \\ nil)

View Source (since 0.1.0)
build(factory(), Enum.t() | nil) :: struct()

Builds a struct with given factory_or_alias module.

If the given factory exports the example/0 function it will use to return the struct and its values. Otherwise, if the module is a struct it will use its default values.

If will override the generated data with the given attrs.

Examples

iex> ExZample.build(User)
%ExZample.User{}

iex> ExZample.build(UserFactory)
%ExZample.User{age: 21, email: "test@test.test", first_name: "First Name", id: 1, last_name: "Last Name"}

iex> ExZample.build(:book)
%ExZample.Book{code: "1321", title: "The Book's Title"}

iex> ExZample.build(User, age: 45)
%ExZample.User{age: 45}

iex> ExZample.build(UserFactory, age: 45)
%ExZample.User{age: 45, email: "test@test.test", first_name: "First Name", id: 1, last_name: "Last Name"}

iex> ExZample.build(:book, code: "007")
%ExZample.Book{code: "007", title: "The Book's Title"}
Link to this function

build_list(count, factory, attrs \\ nil)

View Source (since 0.2.0)
build_list(count :: pos_integer(), factory(), attrs :: Enum.t() | nil) :: [
  struct()
]

Same as build/2, but returns a list with where the size is the given count.

Examples

iex> ExZample.build_list(3, User)
[%ExZample.User{}, %ExZample.User{}, %ExZample.User{}]

iex> ExZample.build_list(3, :book)
[%ExZample.Book{},%ExZample.Book{}, %ExZample.Book{}]

iex> ExZample.build_list(3, User, age: 45)
[%ExZample.User{age: 45}, %ExZample.User{age: 45}, %ExZample.User{age: 45}]

iex> ExZample.build_list(3, :book, code: "007")
[%ExZample.Book{code: "007"},%ExZample.Book{code: "007"}, %ExZample.Book{code: "007"}]
Link to this function

build_pair(factory, attrs \\ nil)

View Source (since 0.2.0)
build_pair(factory(), attrs :: Enum.t() | nil) :: {struct(), struct()}

Same as build/2, but returns a tuple with a pair of structs.

Examples

iex> ExZample.build_pair(User)
{%ExZample.User{}, %ExZample.User{}}

iex> ExZample.build_pair(:book)
{%ExZample.Book{},%ExZample.Book{}}

iex> ExZample.build_pair(User, age: 45)
{%ExZample.User{age: 45}, %ExZample.User{age: 45}}

iex> ExZample.build_pair(:book, code: "007")
{%ExZample.Book{code: "007"},%ExZample.Book{code: "007"}}
Link to this function

config_aliases(aliases)

View Source (since 0.4.0)
config_aliases(%{required(atom()) => factory()}) :: :ok

Creates aliases for your factories to simplify the build calls.

A aliases should be a map with atom keys and values as factory compatible modules. If you call with repeated keys this function will fail. This function is ideal to be called once, for example in your test_helper.ex file.

Examples

iex> ExZample.config_aliases(%{user: UserFactory})
...> ExZample.build(:user)
%User{age: 21, email: "test@test.test", first_name: "First Name", id: 1, last_name: "Last Name"}
Link to this function

config_aliases(scope, aliases)

View Source (since 0.4.0)
config_aliases(atom(), %{required(atom()) => factory()}) :: :ok

Same as config_aliases/1, but you can define a different scope.

This function is specially useful for umbrella apps where each app can define their factories without leaking any aliases to other apps. You can enforce the current scope with ex_zample/1.

Examples

iex> ExZample.config_aliases(:my_app, %{user: UserFactory})
...> ExZample.ex_zample(%{ex_zample_scope: :my_app})
...> ExZample.build(:user)
%User{age: 21, email: "test@test.test", first_name: "First Name", id: 1, last_name: "Last Name"}
Link to this function

create_sequence(name)

View Source (since 0.4.0)
create_sequence(atom()) :: :ok

Creates a sequence with the given name.

A sequence is global runtime counter that can be invoked with sequence/1. The default counter starts from 1 and increments 1 by 1.

Examples

iex> ExZample.create_sequence(:customer_id)
...> Enum.map(1..10, fn _ -> ExZample.sequence(:customer_id) end)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Link to this function

create_sequence(scope_or_name, sequence_fun_or_name)

View Source (since 0.4.0)
create_sequence(
  scope_or_name :: atom(),
  sequence_fun_or_name :: sequence_fun() | atom()
) :: :ok

Same as create_sequence/1, but you can define a different scope or a sequence function.

When use with scope and name you define scoped global counter, it's useful for umbrella apps for example.

When you use name and sequence_fun, the given function will receive the counter and then you can transform in anything you want.

Examples

iex> ExZample.create_sequence(:my_app, :customer_id)
...> ExZample.ex_zample(%{ex_zample_scope: :my_app})
...> ExZample.sequence(:customer_id)
1

iex> ExZample.create_sequence(:customer_id, &("customer_" <> to_string(&1)))
...> Enum.map(1..3, fn _ -> ExZample.sequence(:customer_id) end)
["customer_1", "customer_2", "customer_3"]
Link to this function

create_sequence(scope, name, sequence_fun)

View Source (since 0.4.0)
create_sequence(atom(), atom(), sequence_fun()) :: :ok

Same as create_sequence/1, but you can define a different scope and a sequence function.

The scope is where where your global counter will lives, useful for umbrella apps for example. The given sequence_fun will receive the counter and then you can transform in anything you want.

Examples

iex> ExZample.create_sequence(:my_app, :customer_id, &("customer_" <> to_string(&1)))
...> ExZample.ex_zample(%{ex_zample_scope: :my_app})
...> Enum.map(1..3, fn _ -> ExZample.sequence(:customer_id) end)
["customer_1", "customer_2", "customer_3"]
Link to this function

ex_zample(settings)

View Source (since 0.3.0)
ex_zample(map()) :: :ok

Utiliy function that you can define severial settings that ExZample will look for before executing their functions.

Options

  • :ex_zample_scope, the scope that ExZample should look up for aliases. If no scope is defined, :global is the default scope.
  • :ex_zample_ecto_repo, the Ecto repo that ExZample should use to run their insert functions.

This function works well with setup/1 callback of ExUnit and @tags. For example:

defmodule MyTest do
  use ExUnit.Case
  import ExZample

  @moduletag ex_zample_scope: :my_app

  setup :ex_zample

  test "returns a user" do
    assert %User{} == build(:user)
  end
end

In the example above, ExZample will look for a factory registered in alias :user in the :my_app scope.

Link to this function

insert(factory, attributes \\ nil)

View Source (since 0.10.0)
insert(factory(), Enum.t() | nil) :: struct()

Inserts in the repository the example built by the factory_or_alias module.

If the given factory exports the c:repo/0 function it will use it call the insert! function. Beyond that, it works similar as build/2.

If will override the generated data with the given attributes.

Options

  • ecto_opts, when given, it will be forwarded to the second argument of Ecto.Repo.insert/2

Examples

iex> ExZample.insert(:player)
%ExZample.RPG.Player{}

iex> ExZample.insert(:player, email: "testmail")
%ExZample.RPG.Player{email: "testmail"}
Link to this function

insert(factory, attributes, opts)

View Source (since 0.10.0)
insert(factory(), Enum.t() | nil, Keyword.t()) :: struct()

Same as insert/2, but the attributes and opts are explicit separated.

Options

  • ecto_opts, when given, it will be forwarded to the second argument of Ecto.Repo.insert/2

Examples

iex> ExZample.insert(:player, %{email: "testmail"}, ecto_opts: [prefix: "private"])
%ExZample.RPG.Player{email: "testmail"}
Link to this function

insert_list(count, factory, attributes \\ nil)

View Source (since 0.10.0)
insert_list(pos_integer(), factory(), Enum.t() | nil) :: [struct()]

Same as insert/2, but returns a list with where the size is the given count.

Examples

iex> ExZample.insert_list(3, :character)
[%ExZample.RPG.Character{}, %ExZample.RPG.Character{}, %ExZample.RPG.Character{}]

iex> ExZample.insert_list(3, :character, name: "Todd")
[%ExZample.RPG.Character{name: "Todd"}, %ExZample.RPG.Character{name: "Todd"}, %ExZample.RPG.Character{name: "Todd"}]
Link to this function

insert_list(count, factory, attributes, opts)

View Source (since 0.10.0)
insert_list(pos_integer(), factory(), Enum.t() | nil, Keyword.t()) :: [struct()]

Same as insert/3, but returns a list with where the size is the given count.

Examples

iex> ExZample.insert_list(3, :character, %{name: "Todd"}, ecto_opts: [prefix: "private"])
[%ExZample.RPG.Character{name: "Todd"}, %ExZample.RPG.Character{name: "Todd"}, %ExZample.RPG.Character{name: "Todd"}]
Link to this function

insert_pair(factory, attributes \\ nil)

View Source (since 0.10.0)
insert_pair(factory(), Enum.t() | nil) :: {struct(), struct()}

Same as insert/2, but returns a tuple with a pair of structs.

Examples

iex> ExZample.insert_pair(:character)
{%ExZample.RPG.Character{}, %ExZample.RPG.Character{}}

iex> ExZample.insert_pair(:character, name: "Todd")
{%ExZample.RPG.Character{name: "Todd"}, %ExZample.RPG.Character{name: "Todd"}}
Link to this function

insert_pair(factory, attributes, opts)

View Source (since 0.10.0)
insert_pair(factory(), Enum.t() | nil, Keyword.t()) :: {struct(), struct()}

Same as insert/3, but returns a tuple with a pair of structs.

Examples

iex> ExZample.insert_pair(:character, %{name: "Todd"}, ecto_opts: [prefix: "private"])
{%ExZample.RPG.Character{name: "Todd"}, %ExZample.RPG.Character{name: "Todd"}}
Link to this function

map_for(factory, attributes \\ nil)

View Source (since 0.8.0)
map_for(factory(), Enum.t() | nil) :: map()

Builds a map with given factory_or_alias module. Has the same mechanism of build/2.

Examples

iex> ExZample.map_for(User)
%{age: nil, email: nil, first_name: nil, id: nil, last_name: nil}

iex> ExZample.map_for(UserFactory)
%{age: 21, email: "test@test.test", first_name: "First Name", id: 1, last_name: "Last Name"}

iex> ExZample.map_for(:book)
%{code: "1321", title: "The Book's Title"}

iex> ExZample.map_for(User, age: 45)
%{age: 45, email: nil, first_name: nil, id: nil, last_name: nil}

iex> ExZample.map_for(UserFactory, age: 45)
%{age: 45, email: "test@test.test", first_name: "First Name", id: 1, last_name: "Last Name"}

iex> ExZample.map_for(:book, code: "007")
%{code: "007", title: "The Book's Title"}
Link to this function

map_list_for(count, factory, attrs \\ nil)

View Source (since 0.8.0)
map_list_for(count :: pos_integer(), factory(), attrs :: Enum.t() | nil) :: [
  struct()
]

Same as map_for/2, but returns a list with where the size is the given count.

Examples

iex> ExZample.map_list_for(3, User)
[%{age: nil, email: nil, first_name: nil, id: nil, last_name: nil},
%{age: nil, email: nil, first_name: nil, id: nil, last_name: nil},
%{age: nil, email: nil, first_name: nil, id: nil, last_name: nil}]

iex> ExZample.map_list_for(3, :book)
[%{code: "1321", title: "The Book's Title"},
%{code: "1321", title: "The Book's Title"},
%{code: "1321", title: "The Book's Title"}]

iex> ExZample.map_list_for(3, User, age: 45)
[%{age: 45, email: nil, first_name: nil, id: nil, last_name: nil},
%{age: 45, email: nil, first_name: nil, id: nil, last_name: nil},
%{age: 45, email: nil, first_name: nil, id: nil, last_name: nil}]

iex> ExZample.map_list_for(3, :book, code: "007")
[%{code: "007", title: "The Book's Title"},
%{code: "007", title: "The Book's Title"},
%{code: "007", title: "The Book's Title"}]
Link to this function

map_pair_for(factory, attrs \\ nil)

View Source (since 0.8.0)
map_pair_for(factory(), attrs :: Enum.t() | nil) :: {struct(), struct()}

Same as map_for/2, but returns a tuple with a pair of maps.

Examples

iex> ExZample.map_pair_for(User)
{%{age: nil, email: nil, first_name: nil, id: nil, last_name: nil},
%{age: nil, email: nil, first_name: nil, id: nil, last_name: nil}}

iex> ExZample.map_pair_for(:book)
{%{code: "1321", title: "The Book's Title"},
%{code: "1321", title: "The Book's Title"}}

iex> ExZample.map_pair_for(User, age: 45)
{%{age: 45, email: nil, first_name: nil, id: nil, last_name: nil},
%{age: 45, email: nil, first_name: nil, id: nil, last_name: nil}}

iex> ExZample.map_pair_for(:book, code: "007")
{%{code: "007", title: "The Book's Title"},
%{code: "007", title: "The Book's Title"}}
Link to this function

params_for(factory, attributes \\ nil)

View Source (since 0.9.0)
params_for(factory(), Enum.t() | nil) :: map()

Builds a map with string keys given factory_or_alias module. Has the same mechanism of build/2. Useful to simulate request parameters in a plug or phoenix controller.

Examples

iex> ExZample.params_for(User)
%{"age" => nil, "email" => nil, "first_name" => nil, "id" => nil, "last_name" => nil}

iex> ExZample.params_for(UserFactory)
%{"age" => 21, "email" => "test@test.test", "first_name" => "First Name", "id" => 1, "last_name" => "Last Name"}

iex> ExZample.params_for(:book)
%{"code" => "1321", "title" => "The Book's Title"}

iex> ExZample.params_for(User, age: 45)
%{"age" => 45, "email" => nil, "first_name" => nil, "id" => nil, "last_name" => nil}

iex> ExZample.params_for(UserFactory, age: 45)
%{"age" => 45, "email" => "test@test.test", "first_name" => "First Name", "id" => 1, "last_name" => "Last Name"}

iex> ExZample.params_for(:book, code: "007")
%{"code" => "007", "title" => "The Book's Title"}
Link to this function

params_list_for(count, factory, attrs \\ nil)

View Source (since 0.9.0)
params_list_for(count :: pos_integer(), factory(), attrs :: Enum.t() | nil) :: [
  struct()
]

Same as params_for/2, but returns a list with where the size is the given count.

Examples

iex> ExZample.params_list_for(3, User)
[%{"age" => nil, "email" => nil, "first_name" => nil, "id" => nil, "last_name" => nil},
%{"age" => nil, "email" => nil, "first_name" => nil, "id" => nil, "last_name" => nil},
%{"age" => nil, "email" => nil, "first_name" => nil, "id" => nil, "last_name" => nil}]

iex> ExZample.params_list_for(3, :book)
[%{"code" => "1321", "title" => "The Book's Title"},
%{"code" => "1321", "title" => "The Book's Title"},
%{"code" => "1321", "title" => "The Book's Title"}]

iex> ExZample.params_list_for(3, User, age: 45)
[%{"age" => 45, "email" => nil, "first_name" => nil, "id" => nil, "last_name" => nil},
%{"age" => 45, "email" => nil, "first_name" => nil, "id" => nil, "last_name" => nil},
%{"age" => 45, "email" => nil, "first_name" => nil, "id" => nil, "last_name" => nil}]

iex> ExZample.params_list_for(3, :book, code: "007")
[%{"code" => "007", "title" => "The Book's Title"},
%{"code" => "007", "title" => "The Book's Title"},
%{"code" => "007", "title" => "The Book's Title"}]
Link to this function

params_pair_for(factory, attrs \\ nil)

View Source (since 0.9.0)
params_pair_for(factory(), attrs :: Enum.t() | nil) :: {struct(), struct()}

Same as params_for/2, but returns a tuple with a pair of maps.

Examples

iex> ExZample.params_pair_for(User)
{%{"age" => nil, "email" => nil, "first_name" => nil, "id" => nil, "last_name" => nil},
%{"age" => nil, "email" => nil, "first_name" => nil, "id" => nil, "last_name" => nil}}

iex> ExZample.params_pair_for(:book)
{%{"code" => "1321", "title" => "The Book's Title"},
%{"code" => "1321", "title" => "The Book's Title"}}

iex> ExZample.params_pair_for(User, age: 45)
{%{"age" => 45, "email" => nil, "first_name" => nil, "id" => nil, "last_name" => nil},
%{"age" => 45, "email" => nil, "first_name" => nil, "id" => nil, "last_name" => nil}}

iex> ExZample.params_pair_for(:book, code: "007")
{%{"code" => "007", "title" => "The Book's Title"},
%{"code" => "007", "title" => "The Book's Title"}}
Link to this function

sequence(name)

View Source (since 0.4.0)
sequence(atom()) :: term()

Returns the current counter registered in the given sequence name.

Examples

iex> ExZample.create_sequence(:customer_id, &("customer_" <> to_string(&1)))
...> ExZample.sequence(:customer_id)
"customer_1"
Link to this function

sequence_list(count, name)

View Source (since 0.4.0)
sequence_list(pos_integer(), atom()) :: [term()]

Same as sequence/1, but returns a list of where the number is determined by the given count.

Examples

iex> ExZample.create_sequence(:customer_id, &("customer_" <> to_string(&1)))
...> ExZample.sequence_list(3, :customer_id)
["customer_1", "customer_2", "customer_3"]
Link to this function

sequence_pair(name)

View Source (since 0.4.0)
sequence_pair(atom()) :: {term(), term()}

Same as sequence/1, but returns a pair of sequence items.

Examples

iex> ExZample.create_sequence(:customer_id, &("customer_" <> to_string(&1)))
...> ExZample.sequence_pair(:customer_id)
{"customer_1", "customer_2"}

Link to this section Callbacks

Link to this callback

ecto_repo()

View Source (optional) (since 0.10.0)
ecto_repo() :: module()

Invoked every time you insert your data using ExZample module.

You need to return the Ecto Repo module that ExZample should use to insert records in database

This callback is optional if the goal is to use only in memory.

Link to this callback

example()

View Source (optional) (since 0.1.0)
example() :: struct()

Invoked every time you build your data using ExZample module.

You need to return a struct with example values.

This callback is optional when the module given is a struct. It will use the struct default values if no callback is given.

Link to this callback

example(attrs)

View Source (optional) (since 0.5.0)
example(attrs :: map()) :: struct()

Same as example/0, but here you have the full control in how will build your struct given the attributes.

The keyword list given in functions like build/2 are transformed in map for your convenience and you need to return a struct.

You can have two scenarios when using this callback:

  1. If you define example/0 and example/1 in same factory, example/0 will be prefered when you use build/1. The example/1 will preferend if you use with build/2.

  2. If you only implement example/1 and use build/1, your callback will invoked with an empty map.

This callback is optional.