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
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.
Related
I have a function that intentionally throws when its first argument is the atom throw.
A simplified version of this code is:
-module(sample).
-export([main/1, throw_or_ok/1]).
main(_Args) ->
throw_or_ok(throw).
throw_or_ok(Action) ->
case Action of
throw -> throw("throwing");
ok -> ok
end.
Dialyzer errors on the call to throw_or_ok:
sample.erl:7: The call sample:throw_or_ok
('throw') will never return since it differs in the 1st argument from the success typing arguments:
('ok')
Adding specs doesn't help, the error message is the same:
-module(sample).
-export([main/1, throw_or_ok/1]).
-spec main(_) -> no_return().
main(_Args) ->
throw_or_ok(throw).
-spec throw_or_ok(throw) -> no_return(); (ok) -> ok.
throw_or_ok(Action) ->
case Action of
throw -> throw("throwing");
ok -> ok
end.
How can I get Dialyzer to accept calls to throw_or_ok/1 that are guaranteed to throw?
Unfortunately there is currently no clean way to mark this as acceptable for Dialyzer via specs.
Perhaps you can use an ignore warning annotation, however.
Looks like if will put throw it will never return, if will put ok the pattern will never match with throw. See topic with similar issue. The logic of main/1 need to change, eg:
main(Args) ->
MaybeOk = case Args of
0 -> throw;
_ -> ok
end,
throw_or_ok(MaybeOk).
OR
main(_Args) ->
throw_or_ok(_Args).
I'm trying to meck out a call to application:get_env, but I'm testing a function that calls it with two different sets of arguments.
I setup two separate meck:expect calls like this, but when the function I'm testing tries to call application:get_env(my_app, my_param_one) it fails and throws error:function_clause with undefined.
meck:expect(application, get_env, fun(my_app, my_param_one) -> {ok, "my_value_one"} end),
meck:expect(application, get_env, fun(my_app, my_param_two) -> {ok, "my_value_two"} end),
How can I meck out the same function, with differents sets of parameter values?
The second meck is overwriting the first.
Whenever you define a function in Erlang by pattern-matching on different sets of values, you separate each set of patterns with a semicolon, like this:
-module(sample).
-export([create_greeting/2]).
create_greeting("Grant", _Greeting) -> io:format("Good day sir!");
create_greeting(Name, Greeting) -> io:format("~s, ~s!", [Greeting, Name]).
Similarly, when you setup your meck statements, define the function once, but separate each set of patterns/arguments with a semicolon, like this:
meck:expect(application, get_env, fun(my_app, my_param_one) -> {ok, "my_value_one"};
(my_app, my_param_two) -> {ok, "my_value_two"}
end),
In the LYSE book the author handles the termination of the server as follows:
%% Synchronous call
close_shop(Pid) -> gen_server:call(Pid, terminate).
handle_call(terminate, _From, Cats) ->
{stop, normal, ok, Cats}.
terminate(normal, Cats) ->
[io:format("~p was set free.~n",[C#cat.name]) || C <- Cats],
ok.
So it returns a stop value from the handle_call callback.
Here is how I wrote it:
close_shop(Pid) -> gen_server:stop(Pid).
terminate(_Reason, {Cats, Money}) ->
io:format("Made $~w~n", [Money]),
[io:format("~p was set free.~n",[C#cat.name]) || C <- Cats].
Is this not a good practice then to call gen_server:stop() directly?
It is not a bad practice to call gen_server:stop/1,3 directly. It does an almost same thing as the example from LYSE but without calling handle_call/3 from your module. Try and check it out. You can even read the source code to be sure.
I need to debug some module in foreign system. The module has public function foo() - how can I know place (module and function name)
from which foo() given module was called? I mean stack of calls.
I cannot stop system, all work I can do by reload this module (but with some debug info).
-module(given).
-export(foo/0).
foo() ->
%% here is my debug - and
%% i need here(!) known about unknown_module:unknown_foo!
ok.
---
-module(unknown_module).
..
unknown_foo() ->
given:foo(). %% see above
Here's a simple trick:
Trace = try throw(42) catch 42 -> erlang:get_stacktrace() end,
erlang:display(Trace)
This might work:
where_am_i() ->
try throw(a)
catch throw:a:Stacktrace ->
Stacktrace
end.
Except that it doesn't work for tail calls. For example, given these two functions:
foo() ->
where_am_i().
bar() ->
X = where_am_i(),
{ok, X}.
I get these results:
4> foo:foo().
[{foo,where_am_i,0},
{erl_eval,do_apply,5},
{shell,exprs,6},
{shell,eval_exprs,6},
{shell,eval_loop,3}]
5> foo:bar().
{ok,[{foo,where_am_i,0},
{foo,bar,0},
{erl_eval,do_apply,5},
{shell,exprs,6},
{shell,eval_exprs,6},
{shell,eval_loop,3}]}
That is, I can only see bar, since foo's call frame has been left already when where_am_i is called.
io:format("~s~n", [element(2, process_info(self(), backtrace))]).
self() can be replaced by any other pid (rpc:pinfo should even work with remote procs). This helps if you cannot even modify the source or beam.
Here is my code for doing this:
format_stack_entry(S) ->
{Module,Fun,Arity,[{file,File},{line,Line}]}=S,
io_lib:format("{~p,~p,~p,[{file,~p},{line,~p]}",[Module,Fun,Arity,File,Line]).
stacktop([Top|_]) ->
Top.
ancestor(N) ->
{_,Stacktrace}=erlang:process_info(self(),current_stacktrace),
ancestor(N+1,Stacktrace).
ancestor(1,S) ->
format_stack_entry(stacktop(S));
ancestor(N,[_|T]) ->
ancestor(N-1,T).
info(Format) -> io:format(lists:concat([ancestor(2),Format,"\r"])).
info(Format,Args) -> io:format(lists:concat([ancestor(2),Format,"\r"]),Args).
Lists is a custom module in the system. Use your foo module instead.
I want to call xyz with the name of a function to be invoked.
-module(sample).
-export([xyz/1]).
xyz(Name) -> Name().
p() -> "you called p".
g() -> "you called g".
But I get the following error:
1> c(sample.erl).
./sample.erl:6: Warning: function p/0 is unused
./sample.erl:7: Warning: function g/0 is unused
{ok,sample}
2> sample:xyz('p').
** exception error: bad function p
in function sample:xyz/1
3>
It is correct that you have to export p and g. You can then use apply/3 to call it.
erlang:apply(sample, p, []).
Only fun-values are usable with the Fun(...) syntax. You are passing in an atom-value. An atom is a 'bad function' as the error message go. You could do something similar to
xyz(p) -> fun p/0;
xyz(g) -> fun g/0.
Then go ahead and call
Fun = xyz(p),
Fun()
-module(sample).
-export([xyz/1, p/0, g/0]).
xyz(Name) -> ?MODULE:Name().
p() -> "you called p".
g() -> "you called g".
1> sample:xyz(p).
"you called p"
Pattern match is the idiom to use:
-module(sample).
-export([xyz/1]).
xyz(p) -> p();
xyz(q) -> g().
p() -> "you called p".
g() -> "you called g".
If you want to be dynamic you can use a gen_event server.
Essentially what this is is a server that holds a state which consists of key/function pair like so:
[{p, #func1},
{g, #func2},
{..., ...},
...]
You can then essentially bind events to functions. (there is, needless to say, a bit more to it than that.
The easiest way to do is to try exporting p and g along with xyz.
-export([xyz/1, p/0,g/0]).
After exporting the function p and g can be called as follows :
1> sample:xyz(fun sample:p/0).
"you called p"
2> sample:xyz(fun sample:g/0).
"you called g"
Another way to look at it is that (depending on the problem you're solving) dynamic calls to functions isn't necessarily the right approach. Given that processes and message passing are the way you organize your code in Erlang since it's a "concurrency oriented language", maybe you could just use message passing with a selective receive rather than mimicking idioms of a sequential language? Send a message for what you want and get the custom reply based on that. It's about the result of each function, not the function itself, after all. (Plus there's the flexibility and scalability of message passing, etc.)
Although processes aren't totally free compared to calling from a library module, Erlang-level processes are dirt cheap (especially if the message communication is within the same node). They're not OS-level processes. The overhead would be comparable (or better) to dynamic function calls and object instantiation in heavier scripting languages.