elixir_mock v0.2.9 ElixirMock.Matchers
Contains utility functions that allow predicate-based matching against arguments passed to mock function calls.
The ElixirMock.assert_called/1
and ElixirMock.refute_called/1
macros can take matchers in place of literal arguments
in function call verifications. A matcher is any tuple of the form {:matches, &matcher_fn/1}
where matcher_fn
is a
function of arity 1 that returns a boolean given a value. That value is an argument passed to a call to the mock
function in the same position as the matcher as declared in the call verification statement.
Example
defmodule MyTest do
use ExUnit.Case
require ElixirMock
import ElixirMock
defmodule MyModule do
def add(a, b), do: a + b
end
test "add was called with an even number as the first argument" do
an_even_number = fn(number) -> rem(number, 2) == 0 end
mock = mock_of MyModule
mock.add(4, 3)
assert_called mock.add({:matches, an_even_number}, 3) # passes
assert_called mock.add(4, {:matches, an_even_number}) # fails!
end
end
The ElixirMock.Matchers
module contains functions for common matching use cases like matching any argument,
matching only number arguments, e.t.c. See this module's functions list for a list of in-built matchers.
Deep matching with maps
When a function under test is expecting map arguments, matchers can be used in the match expression for some or all
of the map's keys. When a value of a key in an call verification statement is found to be a matcher expression, the
matcher expression is evaluated with the corresponding value in the actual map argument. If all present matchers in the
expected map evaluate to true
for the corresponding values in the actual map and the values of all the other keys
in the expected map match the values of the same keys in the actual map, the call verification statement passes.
defmodule MyTest do
use ExUnit.Case
require ElixirMock
import ElixirMock
alias ElixirMock.Matchers
defmodule MyModule do
def echo(what_to_say), do: IO.puts(inspect(what_to_say))
end
test "echo/1 should have been called with the correct map" do
mock = mock_of MyModule
mock.echo %{a: 1, b: :something}
assert_called mock.echo(%{a: Matchers.any(:int), b: Matchers.any(:atom)}) # passes
end
end
Also, note that:
- All the matchers availabe in this module can be used within maps in this fashion.
- Matching on map values with matchers can be done with nested maps of arbitrary depth.
Link to this section Summary
Functions
A matcher that matches any argument.
A matcher that matches an argument only if it is of a specified type.
A get-out-of-jail matcher that helps you literally match arguments that look like matchers
Link to this section Functions
any()
A matcher that matches any argument.
Use it when you don't care about some or all arguments in a function call assertion. Also, since ElixirMock.assert_called/1
and ElixirMock.refute_called/1
will not match function calls with different number of arguments from what the assertion
specifies, the any/0
matcher is necessary to be able do assertions like the one in the example below
Example:
defmodule MyTest do
use ExUnit.Case
require ElixirMock
import ElixirMock
alias ElixirMock.Matchers
defmodule MyModule do
def echo(arg), do: IO.puts(arg)
end
test "echo was called with any argument" do
mock = mock_of MyModule
mock.echo("hello")
# If just want to verify that '&echo/1' was called but I don't care about the arguments:
assert_called mock.echo(Matchers.any) # passes
# But this will not pass:
assert_called mock.echo # fails!
end
end
any(type)
A matcher that matches an argument only if it is of a specified type.
Supported types are :atom
, :binary
, :boolean
, :float
, :function
, :integer
, :list
, :map
, :number
,
:pid
, :tuple
, any struct (e.g., %Person{}
), and :_
(equivalent to using any/0
). An ArgumentError
is thrown
if an argument not in this list is passed to the function.
Example:
defmodule MyTest do
use ExUnit.Case
require ElixirMock
import ElixirMock
alias ElixirMock.Matchers
defmodule MyModule do
def echo(arg), do: IO.puts(arg)
end
test "echo was called with a float" do
mock = mock_of MyModule
mock.echo(10.5)
assert_called mock.echo(Matchers.any(:float)) # passes
assert_called mock.echo(Matchers.any(:integer)) # fails!
end
end
literal(value)
A get-out-of-jail matcher that helps you literally match arguments that look like matchers
When ElixirMock finds an argument that looks like {:matches, other_thing}
in a function call verification, it will
assume that other_thing
is a function that is supposed to be used to match an argument. In the rare case that you
need to match an argument that is literally {:matches, other_thing}
, use this matcher. It will tell ElixirMock
not to think about it as a matcher expression but rather as a literal value.
Example:
defmodule MyTest do
use ExUnit.Case
require ElixirMock
import ElixirMock
alias ElixirMock.Matchers
defmodule MyModule do
def echo(arg), do: IO.puts(arg)
end
test "echo was called with a float" do
mock = mock_of MyModule
mock.echo({:matches, 10})
assert_called mock.echo(Matchers.literal({:matches, 10})) # passes
assert_called mock.echo({:matches, 10}) # will blow up!
end
end