Closed amutake closed 7 years ago
Hi! Thanks for a very clean pull request!
What do you imagine the use case of this functionality to be? If you have had a need for this is production, would you mind detailing how you've used it? The reason I'm asking is I'd like to avoid polluting the top level Meck API space if possible. :smile:
(I think the work makes a lot of sense anyway, so one possibility is to add it to the meck_history
module and expose a public API from there instead.)
I'm sorry for my late and thank you for your feedback!
One of my usecases of result
is to test gen_server
's handle_cast
, handle_call
, and handle_info
(i.e., functions passed state
as an argument).
Our production code has a process monitoring server like the following:
-module(meck_result_usecase_server).
-behaviour(gen_server).
%% exported apis
-export([start_link/0, monitor/1]).
%% gen_server callbacks
-export([init/1, handle_cast/2, handle_call/3, handle_info/2, terminate/2, code_change/3]).
-record(state, {monitoring_pids = maps:new() :: maps:map(pid(), reference()), ...(complex record)}).
%% -------------
%% Exported APIs
%% -------------
-spec start_link() ->
{ok, pid()}.
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
-spec monitor(pid()) -> ok.
monitor(Pid) ->
gen_server:cast(?MODULE, {monitor, Pid}).
%% --------------------
%% gen_server callbacks
%% --------------------
init([]) ->
{ok, #state{}}.
handle_cast({monitor, Pid}, State = #state{monitoring_pids = Map}) ->
Ref = erlang:monitor(process, Pid),
{noreply, State#state{monitoring_pids = Map#{Pid => Ref}}};
handle_cast(_Req, State) ->
{noreply, State}.
handle_call(_Req, _From, State) ->
{noreply, State}.
handle_info({'DOWN', Ref, process, Pid, _Reason}, State = #state{monitoring_pids = Map}) ->
case maps:find(Pid, Map) of
{ok, Ref} ->
{noreply, State#state{monitoring_pids = maps:remove(Pid, Map)}};
_ ->
{stop, not_monitored, State}
end;
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
and eunit:
-module(meck_result_usecase_server_tests).
-include_lib("eunit/include/eunit.hrl").
%% eunit
meck_result_usecase_server_test_() ->
{setup,
fun() ->
meck:new(meck_result_usecase_server, [unlink, passthrough]),
{ok, Pid} = meck_result_usecase_server:start_link(),
Pid
end,
fun(Pid) ->
process_flag(trap_exit, true),
exit(Pid, shutdown),
meck:unload(),
ok
end,
fun(_) ->
fun() ->
Pid = spawn(timer, sleep, [infinity]),
ok = meck_result_usecase_server:monitor(Pid),
meck:wait(meck_result_usecase_server, handle_cast, 2, 3000),
exit(Pid, kill),
meck:wait(meck_result_usecase_server, handle_info, 2, 3000),
{Type, _} = meck:result(last, meck_result_usecase_server, handle_info, 2),
?assertEqual(noreply, Type) %% check that `Type' is `noreply', not `stop'
end
end}.
I want to check that handle_info
returns noreply
, not stop
.
One way is directly calling of handle_info
, but I don't want to make state
(which is the 2nd argument of handle_info
, and a very complex record) by using tuple.
So I want to use a function like result
.
To debug test cases, I often want to confirm the result of a particular function using ?debugVal
.
It is OK to achieve this purpose by meck:history/1
, but using meck:history/1
with ?debugVal
is not useable a bit because: (1) annoying function information not concerned, (2) ?debugVal
often omit the result of meck:history/1
.
meck_history
I'm no problem if this function becomes available in toplevel or meck_history
, but in my opinion, it should be a member of toplevel APIs like capture/5-6
because result/4-5
(return the result of a particular function) are duals of capture/5-6
(return the argument of a particular function) and capture/5-6
are members of toplevel APIs.
Sorry for the long silence 🙇
If you move the functions into the history module, I'd be happy accepting the patch. For now, I don't want to add more functions to the main Meck API.
OK!
I have removed the functions from meck
module instead of moving the functions into meck_history
because meck:result/4-5
is almost same as meck_history:result/5
.
Is it OK?
Yes, that looks good. One final request: Can you squash everything into one commit detailing only the change to meck_history
? Looks cleaner that way...
I can also do it while merging, but I'm not sure you'll retain your authorship that way 🙂
I've squashed!
Great work, thanks again!
Thank you!
Hi! Thank you for the nice library.
I would like a function that returns the result value of a specified function, like follows.
I implemented
meck:result(Occur, Mod, Func, OptArgsSpec)
andmeck:result(Occur, Mod, Func, OptArgsSpec, OptCallerPid)
. What do you think about this?