Skip to content

Commit

Permalink
docs: add pattern matching examples for assert_called (#112)
Browse files Browse the repository at this point in the history
* docs: add pattern matching examples for assert_called
* docs: update table of contents
  • Loading branch information
superhawk610 authored and Olshansk committed Dec 9, 2019
1 parent dc5938a commit ae887cf
Showing 1 changed file with 87 additions and 0 deletions.
87 changes: 87 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ See the full [reference documentation](https://hexdocs.pm/mock/Mock.html).
* [Assert called - assert a specific function was called](#Assert-called---assert-a-specific-function-was-called)
* [Assert called - specific value](#Assert-called---specific-value)
* [Assert called - wildcard](#Assert-called---wildcard)
* [Assert called - pattern matching](#Assert-called---pattern-matching)
* [NOT SUPPORTED - Mocking internal function calls](#NOT-SUPPORTED---Mocking-internal-function-calls)
* [Tips](#Tips)
* [Help](#Help)
Expand Down Expand Up @@ -284,6 +285,92 @@ defmodule MyTest do
end
````

### Assert called - pattern matching

`assert_called` will check argument equality using `==` semantics, not pattern matching.
For structs, you must provide every property present on the argument as it was called or
it will fail. To use pattern matching (useful when you only care about a few properties on
the argument or need to perform advanced matching like regex matching), provide custom
argument matcher(s) using [`:meck.is/1`](https://hexdocs.pm/meck/meck.html#is-1).

```` elixir
defmodule User do
defstruct [:id, :name, :email]
end

defmodule Network do
def update(%User{} = user), do: # ...
end

defmodule MyTest do
use ExUnit.Case, async: false

import Mock

test "test_name" do
with_mock Network, [update: fn(_user) -> :ok end] do
user = %User{id: 1, name: "Jane Doe", email: "[email protected]"}
Network.update(user)

assert_called Network.update(
:meck.is(fn user ->
assert user.__struct__ = User
assert user.id = 1

# matcher must return true when the match succeeds
true
end)
)
end
end
end
````

You can use any valid Elixir pattern matching/multiple function heads to accomplish
this more succinctly, but remember that the matcher will be executed for _all_ function
calls, so be sure to include a fallback case that returns `false`. For mocked functions
with multiple arguments, you must include a matcher/pattern for each argument.

```` elixir
defmodule Network.V2 do
def update(%User{} = user, changes), do: # ...

def update(id, changes) when is_integer(id), do: # ...

def update(_, _), do: # ...
end

defmodule MyTest do
use ExUnit.Case, async: false

import Mock

test "test_name" do
Network.V2.update(%User{id: 456, name: "Jane Doe"}, %{name: "John Doe"})
Network.V2.update(123, %{name: "John Doe", email: "[email protected]"})
Network.V2.update(nil, %{})

# assert that `update` was called with user id 456
assert_called Network.V2.update(
:meck.is(fn
%User{id: 456} -> true
_ -> false
end),
:_
)

# assert that `update` was called with an email change
assert_called Network.V2.update(
:_,
:meck.is(fn
%{email: "[email protected]"} -> true
_ -> false
end)
)
end
end
````

## NOT SUPPORTED - Mocking internal function calls

A common issue a lot of developers run into is Mock's lack of support for mocking
Expand Down

0 comments on commit ae887cf

Please sign in to comment.