patch v0.1.2 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.

Limitations

Patch currently can only mock out functions of arity /0 - /10. If a function with greater arity needs to be patched this module will need to be updated.

Link to this section Summary

Functions

Patches a function in a module

Spies on the provided module

Link to this section Functions

Link to this macro

assert_called(arg)

View Source (macro)
Link to this function

patch(module, function, mock)

View Source
patch(module(), function(), mock) :: mock when mock: function()
patch(module(), function(), 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 macro

refute_called(arg)

View Source (macro)

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.