[erlang-questions] testing side effects of asynchronous code

Klas Johansson <>
Fri Jan 6 20:02:19 CET 2012


2012/1/2 Motiejus Jakštys <>:
> Hi List,
>
> Let's say I am testing side effects of this asynchronous function:
> gateway_api:send(Message) -> reference()
>
> It does some asynchronous processing and produces side effects. After
> processing completes, gen_gwserver:ack_sent is invoked, like this:
> gen_gwserver:ack_sent(Ref :: reference()) -> ok.
>
> The question is: how can I know that the function ack_sent has been
> called? Then I know that asynchronous work has been completed, so I can
> start validating the side effects.
>
> An imaginary API in a test case, which blocks until
> gen_gwserver:ack_sent/1 has been called:
> ?call_and_sleep(
>    gateway_api:send(Message),
>    gen_gwserver, ack_sent, 1
> )
>
> Some options that we ruled out:
> * timer:sleep(some random value)
> * making internal gateway_api:ack(Reference) calls (inconvenient, since
>  necessary only for testing)
> * meck:passthrough looked promising, but the problem is it doesn't
>  return, so it cannot be implemented using meck cleanly.
>
> Thanks,
> Motiejus Jakštys
> _______________________________________________
> erlang-questions mailing list
> 
> http://erlang.org/mailman/listinfo/erlang-questions

Hi,

I'm biased here, but it sounds like mockgyver [1] could help you out.

mockgyver is a mocking library which also lets you verify
side-effects.  There are a number of ways to verify side-effects, but
the one it sounds you're after is the ?WAIT_CALLED macro and you don't
have to (you can, but you don't have to) mock gen_gwserver in order to
use it.  ?WAIT_CALLED relies on erlang traces for non-mocked modules.
Here's how you'd use it from eunit:

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

api_test_() ->
    ?WITH_MOCKED_SETUP(fun setup/0, fun cleanup/1).

setup() ->
    ... start server here, if any ...
    Pid.

cleanup(Pid) ->
    ... stop server here, if any ...

calls_gw_server_ack_test(Pid) ->
    ...
    Ref = gateway_api:send(Message),
    ...
    ?WAIT_CALLED(gen_gwserver:ack_sent(Ref)), % matches only calls
with ref from above
    ... verify side-effects here, perhaps using ?WAS_CALLED ...


Cheers,
Klas

[1] https://github.com/klajo/mockgyver
    https://github.com/klajo/mockgyver/blob/master/doc/mockgyver.md



More information about the erlang-questions mailing list