patch v0.2.0 Patch View Source

Patch - Ergonomic Mocking for Elixir

Patch makes it easy to mock one or more functions in a module returning a value or executing custom logic. Patches and Spies allow tests to assert or refute that function calls have been made.

Patches

When a module is patched, the patched function will return the value provided.

assert "HELLO" = String.upcase("hello")                 # Assertion passes before patching

patch(String, :upcase, :patched_return_value)

assert :patched_return_value == String.upcase("hello")  # Assertion passes after patching

Modules can also be patched to run custom logic instead of returning a static value

assert "HELLO" = String.upcase("hello")                 # Assertion passes before patching

patch(String, :upcase, fn s -> String.length(s) end)

assert 5 == String.upcase("hello")                      # Assertion passes after patching

Patching Ergonomics

patch/3 returns the value that the patch will return which can be useful for later on in the test. Examine this example code for an example

{:ok, expected} = patch(My.Module, :some_function, {:ok, 123})

... additional testing code ...

assert response.some_function_result == expected

This allows the test author to combine creating fixture data with patching.

Asserting / Refuting Calls

After a patch is applied, tests can assert that an expected call has occurred by using the assert_called macro.

patch(String, :upcase, :patched_return_value)

assert :patched_return_value = String.upcase("hello")   # Assertion passes after patching

assert_called String.upcase("hello")                    # Assertion passes after call

assert_called supports the :_ wildcard atom. In the above example the following assertion would also pass.

assert_called String.upcase(:_)

This can be useful when some of the arguments are complex or uninteresting for the unit test.

Tests can also refute that a call has occurred with the refute_called macro. This macro works in much the same way as assert_called and also supports the :_ wildcard atom.

Spies

If a test wishes to assert / refute calls that happen to a module without actually changing the behavior of the module it can simply spy/1 the module. Spies behave identically to the original module but all calls and return values are recorded so assert_called and refute_called work as expected.

Link to this section Summary

Functions

Asserts that the function has been called with any arity call

Patches a function in a module

Refutes that the function has been called with any arity call

Remove any mocks or spies from the given module

Spies on the provided module

Link to this section Functions

Link to this function

assert_any_call(module, function)

View Source
assert_any_call(module :: module(), function :: atom()) :: nil

Asserts that the function has been called with any arity call

Link to this macro

assert_called(arg)

View Source (macro)
Link to this function

patch(module, function, mock)

View Source
patch(module :: module(), function :: atom(), mock) :: mock
when mock: (... -> any())
patch(module :: module(), function :: atom(), return_value) :: return_value
when return_value: term()

Patches a function in a module

The patched function will either always return the provided value or if a function is provided then the function will be called and its result returned.

Link to this function

refute_any_call(module, function)

View Source
refute_any_call(module :: module(), function :: atom()) :: nil

Refutes that the function has been called with any arity call

Link to this macro

refute_called(arg)

View Source (macro)
Link to this function

restore(module)

View Source
restore(module :: module()) :: :ok

Remove any mocks or spies from the given module

Link to this function

spy(module)

View Source
spy(module :: module()) :: :ok

Spies on the provided module

Once a module has been spied on the calls to that module can be asserted / refuted without changing the behavior of the module.