ExZample v0.7.0 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 the scope that ExZample will look for the aliases. If no scope is defined, :global is the default scope.

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 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(scope)

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

Utiliy function that you can define the scope that ExZample will look for the aliases. If no scope is defined, :global is the default scope.

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

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

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.