Skip to content

Commit

Permalink
Merge pull request #142 from DavidRawk-Blake/allow_assert_called_at_l…
Browse files Browse the repository at this point in the history
…east

Added new function/macro to allow for "at_least" test
  • Loading branch information
jjh42 authored Jan 10, 2024
2 parents df4cc3d + 442accd commit 07081c1
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 0 deletions.
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ See the full [reference documentation](https://hexdocs.pm/mock/Mock.html).
* [Assert call order](#Assert-call-order)
* [Assert not called - assert a specific function was not called](#Assert-not-called---assert-a-specific-function-was-not-called)
* [Assert called exactly - assert a specific function was called exactly x times](#Assert-called-exactly---assert-a-specific-function-was-called-exactly-x-times)
* [Assert called at least - assert a specific function was called at least x times](#Assert-called-at-least---assert-a-specific-function-was-called-at-least-x-times)
* [NOT SUPPORTED - Mocking internal function calls](#NOT-SUPPORTED---Mocking-internal-function-calls)
* [Tips](#Tips)
* [Help](#Help)
Expand Down Expand Up @@ -418,6 +419,34 @@ defmodule MyTest do
end
```

## Assert called at least - assert a specific function was called at least x times

`assert_called_at_least` will assert that a mocked function was called at least the expected number of times.

```elixir
defmodule MyTest do
use ExUnit.Case, async: false

import Mock

test "test_name" do
with_mock HTTPotion, [get: fn(_url) -> "<html></html>" end] do
HTTPotion.get("http://example.com")
HTTPotion.get("http://example.com")
HTTPotion.get("http://example.com")

# Using Wildcard
assert_called_at_least HTTPotion.get(:_), 2

# Using Specific Value
assert_called_at_least HTTPotion.get("http://example.com"), 2
end
end
end
```



### Assert call order

`call_history` will return the `meck.history(Module)` allowing you assert on the order of the function invocation:
Expand Down
30 changes: 30 additions & 0 deletions lib/mock.ex
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,36 @@ defmodule Mock do
end
end

@doc """
Use inside a `with_mock` block to determine whether a mocked function was called
as expected at least x times. If the assertion fails, the number of calls that
were received is displayed in the assertion message.
Pass `:_` as a function argument for wildcard matches.
## Example
assert_called_at_least HTTPotion.get("http://example.com"), 2
# Matches any invocation
assert_called_at_leaset HTTPotion.get(:_), 2
"""
defmacro assert_called_at_least({{:., _, [module, f]}, _, args}, expected_times) do
quote do
unquoted_module = unquote(module)
unquoted_f = unquote(f)
unquoted_args = unquote(args)
unquoted_expected_times = unquote(expected_times)
actual_called_count = :meck.num_calls(unquoted_module, unquoted_f, unquoted_args)

if actual_called_count < unquoted_expected_times do
mfa_str = "#{unquoted_module}.#{unquoted_f}(#{unquoted_args |> Enum.map(&Kernel.inspect/1) |> Enum.join(", ")})"
raise ExUnit.AssertionError,
message: "Expected #{mfa_str} to be called at least #{unquoted_expected_times} time(s), but it was called (number of calls: #{actual_called_count})"
end
end
end

@doc """
Use inside a `with_mock` block to check if
a mocked function was NOT called. If the assertion fails,
Expand Down
19 changes: 19 additions & 0 deletions test/mock_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,25 @@ defmodule MockTest do
end
end

test "assert_called_at_least" do
with_mock String, [reverse: fn(x) -> 2*x end] do
String.reverse(2)
String.reverse(2)
String.reverse(2)
assert_called_at_least(String.reverse(2), 3)
assert_called_at_least(String.reverse(2), 2)

try do
assert_called_at_least(String.reverse(2), 5)
rescue
error in [ExUnit.AssertionError] ->
"""
Expected Elixir.String.reverse(2) to be called at least 5 time(s), but it was called (number of calls: 3)\
""" = error.message
end
end
end

test "assert_not_called" do
with_mock String,
[reverse: fn(x) -> 2*x end] do
Expand Down

0 comments on commit 07081c1

Please sign in to comment.