4

As a newcomer to meck, I've been putting together a test that shows the various features. I cannot, however, understand why a developer might call meck:validate. Here's my example:

-module(meck_demo).

-include_lib("eunit/include/eunit.hrl").

validate_is_of_limited_use_test_() ->
    { foreach, fun setup_mock/0, fun cleanup_mock/1, 
      [fun validate_does_not_fail_if_a_function_is_not_called/0,
       fun validate_does_not_fail_if_a_function_is_called_with_wrong_arity/0,
       fun validate_does_not_fail_if_an_undefined_function_is_called/0,
       fun validate_does_fail_if_a_function_was_called_with_wrong_argument_types/0,
       fun validate_does_fail_if_expectation_throws_an_unexpected_exception/0 ]}.

validate_does_not_fail_if_a_function_is_not_called() ->
    meck:expect(womble, name, fun() -> "Wellington" end),   
    ?assert(meck:validate(womble)).

validate_does_not_fail_if_a_function_is_called_with_wrong_arity() ->
    meck:expect(womble, name, fun() -> "Madame Cholet" end),
    ?assertError(undef, womble:name(unexpected_arg)),
    ?assert(meck:validate(womble)).

validate_does_not_fail_if_an_undefined_function_is_called() ->
    ?assertError(undef, womble:fly()),
    ?assert(meck:validate(womble)).

validate_does_fail_if_a_function_was_called_with_wrong_argument_types() ->
    meck:expect(womble, jump, fun(Height) when Height < 1 -> 
                                ok
                              end),
    ?assertError(function_clause, womble:jump(999)),
    ?assertNot(meck:validate(womble)).

validate_does_fail_if_expectation_throws_an_unexpected_exception() ->
    meck:expect(womble, jump, fun(Height) -> 42 = Height end),
    ?assertError({badmatch, 999}, womble:jump(999)),
    ?assertNot(meck:validate(womble)).   

setup_mock() ->
    meck:new(womble, [non_strict]).

cleanup_mock(_SetupResult) ->
    meck:unload(womble).

What am I missing?

-- Updated to reflect the cases that Adam explains can be caught

MrBlueSky
  • 728
  • 6
  • 20

1 Answers1

5

You managed to hit just about every case not covered by validate (added better documentation in 10c5063).

Validate can detect:

  • When a function was called with the wrong argument types (function_clause)
  • When an exception was thrown
  • When an exception was thrown and expected (via meck:exception/2), which still results in true being return from meck:validate/1

Validate cannot detect:

  • When you didn't call a function
  • When you called a function with the wrong number of arguments
  • If you called an undefined function

The reason it cannot detect these cases is because of how Meck is implemented. Meck replaces the module with a mock and a process that maintains the mock. Everything Meck gets goes through that mock module. Meck does not insert itself at the caller level (i.e. in your module or in your test case), so it cannot know that you failed to call a module. All of the failures in your test case above never reaches the mock module in the first place.

Adam Lindberg
  • 16,447
  • 6
  • 65
  • 85
  • Thanks Adam - that's very helpful. The explanation you gave as to why Meck cannot detect certain misuses makes sense. I've updated my question to reflect the examples you provided. In the cases where validate *does* fail, the test also demonstrates the failure anyway (assertError). So I still don't really understand why a coder would ever actually call validate. – MrBlueSky Apr 10 '17 at 10:57
  • I agree that it's usage is limited. One use case would be that your code under test might not crash, but internally catch too many exceptions. In this case, if your mock is not called correctly, you could use Meck to find out if your code should have crashed or not. – Adam Lindberg Apr 10 '17 at 11:15