[erlang-questions] testing asynchronous code
Scott Lystig Fritchie
fritchie@REDACTED
Tue Apr 20 22:37:40 CEST 2010
Martin DeMello <martindemello@REDACTED> wrote:
>> Martin, you have another option: your test code calls
>> YourModule:handle_cast() directly. If your client side stub looks
>> like:
md> Thanks, some good ideas in there. Not sure I've absorbed it fully,
md> but I'll stare at it till it clicks :) From what I can make out,
md> though, it doesn't handle the case of handle_cast() itself calling
md> cast(), since the intermediate states before the entire tree of
md> casts has completed aren't really of interest. Is that correct, or
md> have I missed something?
You may or may not have missed something, it's tough to tell. If your
test code calls YourModule:handle_cast() and checks the return result,
that checking is easiest if YourModule:handle_cast() is purely
functional. If it has side-effects, then checking for sanity is more
difficult. As John Hughes suggested, trace-based tests might be easier
if you're dealing with lots of side-effects.
It's quite unusual to have a gen_server send itself a message using
gen_server:cast(). I don't know why your code would do it...
... but I confess that it is very occasionally useful to use
gen_server:cast() or "self() ! {some_message_tag, ReminderData}" to
remind yourself to do something that is very inconvenient to deal with
at this instant in time. When your call stack pops the normal way and
returns control to gen_server's message handling loop, then you can
conveniently handle that reminder data via YourModule:handle_cast() or
YourModule:handle_info().
i_am_buried_seven_levels_deep_in_my_call_stack(Args, State) ->
%% Weird args handling stuff can be better handled by sending
%% a (non-blocking!) message to myself. Perhaps this reminder
%% message can look the same as a cast message that I have to
%% handle anyway.
%%
%% One case where this is useful is if this function needs to
%% modify "State", but the structure of the code (including all
%% the intermediate callers between here and handle_cast() is
%% inconvenient to refactor to return a new state var.
%% Refactoring is usually the better choice ... except when
%% it isn't better. It depends.
case is_arg_weird(Args, State) of
true -> gen_server:cast(self(), {arg_was_weird, Args});
false -> ok
end,
%% Do normal, down-in-the-depths calculation here, then return
%% only an atom.
ok.
It's like a continuation, except uglier, except when it's only slightly
ugly. Depends on the context. :-)
-Scott
More information about the erlang-questions
mailing list