Module em

The module name 'em' stands for 'Erly Mock'.

Copyright © (C) 2011-2017 Sven Heyll

Behaviours: gen_statem.

Authors: Sven Heyll (sven.heyll@gmail.com).

Description

The module name 'em' stands for 'Erly Mock'.

This mocking library works similar to Easymock.

After a mock process is started by new/0 it can be programmed to expect function calls and to react to them in two ways:

This is done with strict/4, strict/5, stub/4, stub/5

Before the code under test is executed, the mock must be told that the programming phase is over by replay/1.

In the next phase the code under test is run, and might or might not call the functions mocked. The mock process checks that all functions programmed with strict/4, strict/5 are called in the correct order, with the expected arguments and reacts in the way defined during the programming phase. If a mocked function is called although another function was expected, or if an expected function was called with different arguments, the mock process dies and prints a comprehensive error message before failing the test.

To support mock invokations from multiple processes the strictness requirement can be reduced to calls belonging to the same group. new_groups/2 creates a list of named groups, where calls belongig to different groups may occur in any order. A group is passed as mock reference (1st parameter) to strict/5 or strict/4. Use await/1 with a list of groups to block the caller until all groups are finished, i.e. the expectations assigned to each group via strict/5 were invoked. NOTE: It is prohibited to use the same expectations with different return values among a list groups created together.

At the end of a unit test await_expectations/1 is called to await all invocations defined during the programming phase.

An alternative to await_expectations/1 is verify/1. It is called to check for missing invocations at the end of the programming phase, if any expected invocations are missing at verify will throw an exception.

When the mock process exits it tries hard to remove all modules, that were dynamically created and loaded during the programming phase.

NOTE: This library works by purging the modules mocked and replacing them with dynamically created and compiled code, so be careful what you mock, i.e. it brings chaos to mock modules from kernel. This also implies, that tests that mock the same modules must be run sequentially.

Apart from that, it is very advisable to only mock owned modules anyway.

Also, mocking modules is an operation that mutates the whole erlang virtual machine (more or less), therefore it is advisable to call lock/0 and unlock/0 around a block test code that relies on an intact set of modules, which are not mocked.

Note that all module loading by em is made sequential through a single em_module_loader server.

Data Types

answer()

answer() = {function, fun(([any()]) -> any())} | {return, any()}

args()

args() = [fun((any()) -> true | false) | term()]

group()

group() = {group, pid(), group_tag()}

group_tag()

group_tag() = {term(), reference()}

timeout_millis()

timeout_millis() = non_neg_integer() | infinity

Function Index

any/0 Utility function that can be used as a match function in an argument list to match any value.
await/2 Block until a specific invokation defined via strict/4 during the programming phase was made.
await_expectations/1 Wait until all invokations defined during the programming phase were made.
call_log/1 Retrieve a list of successfully mocked invokations, i.e.
lock/0
new/0 Spawn a linked mock process and return the pid.
new_groups/2 Create a group handle to assign mock expectation to.
nothing/2 This is used to express the expectation that no function of a certain module is called.
replay/1 Finishes the programming phase and switches to the replay phase where the actual code under test may run and invoke the functions mocked.
replay/2 Finishes the programming phase and switches to the replay phase, expecting that invokations are recorded at least once every InvokationTimeout millis.
strict/4 Add an expectation during the programming phase for a specific function invokation.
strict/5 This function behaves like strict/4 and additionally accepts a return value or an answer function.
stub/4 Defines a what happens when a function is called whithout recording any expectations.
stub/5 This is similar stub/4 except that it, like strict/5 allows the definition of a return value or an answer function.
unlock/0 Release lock obtained by lock().
verify/1 Finishes the replay phase.
zelf/0 Utility function that can be used as a match function in an argument list to match self(), e.g.

Function Details

any/0

any() -> fun((any()) -> true)

Utility function that can be used as a match function in an argument list to match any value.

await/2

await(X1::group(), Handle::reference()) -> {success, InvPid::pid(), Args::[term()]} | {error, term()}

Block until a specific invokation defined via strict/4 during the programming phase was made.

The handle for the specific invokation is the value returned by strict/4.

The return value contains the parameters and the pid of the recorded invokation. This function maybe called anytime before or after the referenced invokation has actually happened.

If the handle is not valid, an error is returned.

await_expectations/1

await_expectations(X1::group()) -> ok

Wait until all invokations defined during the programming phase were made. After this functions returns, the mock can be expected to exit and clean up all modules installed.

call_log/1

call_log(X1::group()) -> [{Mod::atom(), Func::atom(), Args::[term()], Answer::term()}]

Retrieve a list of successfully mocked invokations, i.e. all calls that were accepted by the em process in the replay phase. Both strict and stub invokations are recorded. NOTE: The Answer might as well be a function, depending on the return argument passed to strict or stub.

lock/0

lock() -> ok

new/0

new() -> group()

Spawn a linked mock process and return the pid.

This is usually the first thing to do in each unit test. The resulting pid is used in the other functions below.

NOTE: only a single mock proccess is required for a single unit test case. One mock process can mock an arbitrary number of different modules.

When the mock process dies, all uploaded modules are purged from the code server, and all cover compiled modules are restored.

When the process that started the mock exits, the mock automatically cleans up and exits.

After new() the mock is in 'programming' state.

new_groups/2

new_groups(X1::group(), GroupNames::[term()]) -> [group()]

Create a group handle to assign mock expectation to. The result can be passed to strict/4 or strict/5 and await/2.

nothing/2

nothing(X1::group(), Mod::atom()) -> ok

This is used to express the expectation that no function of a certain module is called. This will cause each function call on a module to throw an 'undef' exception.

replay/1

replay(G::group()) -> ok

Finishes the programming phase and switches to the replay phase where the actual code under test may run and invoke the functions mocked. This may be called only once, and only in the programming phase. This also loads (or replaces) the modules of the functions mocked. In the replay phase the code under test may call all mocked functions. If the application calls a mocked function with invalid arguments, or if the application calls a function not expected on a mocked module, the mock process dies and - if used in a typical edoc test suite - fails the test.

replay/2

replay(X1::group(), InvokationTimeout::timeout_millis()) -> ok

Finishes the programming phase and switches to the replay phase, expecting that invokations are recorded at least once every InvokationTimeout millis.

See also: replay/1.

strict/4

strict(M::group(), Mod::atom(), Fun::atom(), Args::args()) -> reference()

Add an expectation during the programming phase for a specific function invokation.

All expectations defined by 'strict' define an order in which the application must call the mocked functions, hence the name 'strict' as oposed to 'stub' (see below).

The parameters are:

This function returns a reference that identifies the expectation. This reference can be passed to await/2 which blocks until the expected invokation happens.

The return value, that the application will get when calling the mocked function in the replay phase is simply the atom ok. This differentiates this function from strict/5, which allows the definition of a custom response function or a custom return value.

NOTE: This function may only be called between new/0 and replay/1 - that is during the programming phase.

strict/5

strict(X1::group(), Mod::atom(), Fun::atom(), Args::args(), Answer::answer()) -> reference()

This function behaves like strict/4 and additionally accepts a return value or an answer function. That parameter Answer may be:

stub/4

stub(M::group(), Mod::atom(), Fun::atom(), Args::args()) -> ok

Defines a what happens when a function is called whithout recording any expectations. The invocations defined by this function may happen in any order any number of times. The way, the invocation is defined is analog to

See also: strict/4.

stub/5

stub(X1::group(), Mod::atom(), Fun::atom(), Args::args(), Answer::answer()) -> ok

This is similar stub/4 except that it, like strict/5 allows the definition of a return value or an answer function.

See also: strict/5, stub/4.

unlock/0

unlock() -> ok

Release lock obtained by lock().

verify/1

verify(X1::group()) -> ok

Finishes the replay phase. If the code under test did not cause all expected invokations defined by strict/4 or strict/5, the call will fail with badmatch with a comprehensive error message. Otherwise the mock process exits normally, returning ok.

zelf/0

zelf() -> atom()

Utility function that can be used as a match function in an argument list to match self(), e.g. when it matches the pid of the process, that calls the funtion during the replay phase.


Generated by EDoc