Closed doubleyou closed 3 years ago
To recap, the following is possible right now with Meck:
seq
/sequence
and loop
)expect
plus a fun with different function headers`)A more robust example of the last case would be:
a_test() ->
meck:expect(mod, f, fun mock/3).
mock(1, Arg2, Arg3) -> 1;
mock(Arg1, 2, Arg3) -> 2;
mock(Arg1, Arg2, Arg3) -> etc.
A more complex method is of course to call some other code or process to do something more advanced. You could check which time it is, how many calls have been made, which process is calling etc. This is essentially a mock with a state and some advanced logic.
It can currently be implemented like so:
a_test() ->
Pid = start(InitState),
meck:expect(mod, f, fun(A1, A2, A3) -> call(Pid, [A1, A2, A3]) end).
start(State) -> spawn_link(fun() -> advanced_mock(State) end).
call(Pid, Args) ->
Pid ! {call, pid(), Args},
receive {reply, Reply} -> Reply end.
advanced_mock(State) ->
receive
{call, From, Args} ->
From ! {reply, do_something(Args, From, State)},
advanced_mock(State)
end.
I agree with what you say, and I think there is a use case for making the last option somewhat easier with Meck, if possible. How, I'm not so sure.
One idea I've toyed with is a meck:put/2
and meck:get/1
that could be called inside a mock to keep state, but it is not very expressive and still forces you to write a lot of boiler plate code.
Just return data from an ETS table I think is also too simplistic. It's just seq
or loop
on steroids.
Ideally, Meck should provide some structure for keeping and modifying state along with an expressive way to define this. Alongside, it should also make it possible to affect that state without triggering complete recompiles.
With multiple function clause specs I think this is currently possible to achieve somewhat satisfactory. Closing this for now. Feel free to open a new issue or discussion about any improvements.
Hi,
Consider the following example. We want some mocked function to return different values in different cases. Normally, this is being done either using something like
meck:seq/1
or by callingmeck:expect/4
in-place.The sequencing approach can be a problem if there's no determined mount of calls to be made. For example, when we have some periodic calls, or when we have a complex call tree that calls our mocked function not once or twice. We may not even care about the amount of function calls made, just the fact that its return value was always the defined one.
Calling
meck:expect/4
in place is much better from the semantics perspective but it's painfully slow, as we recompile the module every time. As a result, simple tests may start taking 5-10 seconds instead of sub-seconds.Is it technically possible to use something like ETS tables for storing
meck:expect
table, or there were some technical limitations that made you require to recompile the module? I ended up having that ETS-based approach for some cases and now wonder ifmeck:expect/4
could be changed to work this way, which is much faster, or another function likemeck:quick_expect/4
can be added as a wrapper, because this seems like a fairly common pattern.Thanks!