views:

20

answers:

1

I have the following init method in a gen_fsm callback module (my_fsm):

init(Args) when length(Args) =:= 2 ->
   % do work with Args here
   {ok, my_state, InitialState}.

There is no other init-method in the callback module.

I want to write a unit test using eunit where I assert that calling gen_fsm with an argument-list that does not contain two elements fails:

start_link_without_args_exits_test() ->
   ?assertException(exit, _, gen_fsm:start_link(my_fsm, [], [])).

However, when the test is run, eunit skips the test with the message:

undefined
*unexpected termination of test process*
::{function_clause,[{my_fsm,init,[[]]},
                    {gen_fsm,init_it,6},
                    {proc_lib,init_p_do_apply,3}]}{proc_lib,init_p_do_apply,3}]}

Why is it that the test does not "catch" this error and reports it as a passed test?

+2  A: 

The exception actually happens in the gen_fsm process. When the call to the init/1 function is made, gen_fsm catches the result. If it sees something like an error, it will send the error back to the parent (through proc_lib:init_ack/1-2) and then call exit(Error).

Because you use start_link and are not trapping exit, you will never receive the return value -- you'll simply crash instead. For your test case, you'll need to either use start or call process_flag(trap_exit,true) in order to obtain the return value rather than just crashing when the other process goes down.

Then you'll need to switch from

?assertException(exit, _, gen_fsm:start_link(my_fsm, [], [])).

to something like

?assertMatch({error,{function_clause,[{my_fsm,init,_} | _]}}, 
             gen_fsm:start_link(my_fsm, [], [])) 

In order to have it working well.

I GIVE TERRIBLE ADVICE
Thanks! You made my day.
Mingus Rude