[erlang-questions] EUnit Help

Chris Bernard cebernard@REDACTED
Fri Jun 11 01:36:20 CEST 2010

I try to answer this help request below, but first I'd like to pose a  
general question to everyone.  I'm interested to hear folks' opinions  
on using EUnit to test Behavior implementations, individually and in  
groups.  Where do you tend to draw the line and say, "Ok, better use  
Common Test for this"?  (and why?)

A few potential answers might be:

a)  EUnit for non-Behaviors, Common Test for the rest
b)  EUnit for single Behaviors without Supervisors, Common Test for  
the rest
c)  EUnit for Applications on one node or machine, Common Test for the  
d)  EUnit for Application functional and integration tests, Common  
Test for system and load testing

More generally, some criteria for this decision could be:

- Control Flow:  Sequential or Concurrent
- Design:  Raw Processes or Behaviors
- Use Case Flow:  Normal or Exception
- Unit Size:  Module, Process Group, Application, Release
- Logical Distribution:  Single or Multiple Nodes
- Physical Distribution:  Local or Distributed

I'm just spitballing here.  Hopefully this is enough to elicit some  
opinions (other than "I Hate Unit Testing) :-)

About a year ago there was an interesting thread here, "EUnit vs.  
Common Test" -- that was a good start to the conversation.  But when I  
look around for open source project examples of using EUnit to test  
Behaviors and Applications, I don't see much yet.  Have I missed one?

Ok, now I'll attempt to answer your question, Alex.  I can't speak to  
any differences in behavior between versions of EUnit.  But...

If you have a gen_server that's trapping exits and you want to use  
EUnit to test the scenario where the gen_server gets sent a shutdown  
request (i.e. exit(Pid, shutdown) or exit(Pid, {shutdown, term()})),  
triggering a call to terminate/2 with Reason indicating shutdown, then  
you need to ensure two things:

1)  the gen_server is not linked to the EUnit process running the test
2)  the gen_server receives the shutdown request from a process to  
which it's linked.

If you just spawn_link this gen_server directly from an EUnit test  
(simple or generated), then the gen_server will be linked to the EUnit  
process, and when it dies, it will kill the EUnit process running the  
test as well.  This generates the error you report.  Since EUnit's  
only means of error detection is via exceptions or timeouts (not EUnit  
process deaths), this error is expected behavior.

(BTW, If you have (1) without (2), the Reason passed to terminate/2 is  
'normal', not 'shutdown' or {shutdown, term()}).

One way to make this work is to simply wrap the calls to start_link()  
and exit() in a fun and spawn it in the test, like this:

foo_shutdown_test() ->
   spawn(fun() ->
     {ok, Pid} = foo:start_link(),
     exit(Pid, shutdown)  % or exit(Pid, {shutdown, any_term()})

But do you really need to start the gen_server to test this?  You can  
get a lot of value from simply calling terminate/2 with fake args to  
simulate scenarios without the extra wrapping/start_linking/exiting.

Things are simpler if you're testing scenarios where a gen_server  
handle_X callback function returns a 'stop' tuple, causing terminate/2  
to be called with a Reason of 'normal' -- or if the terminate/2  
behavior doesn't care about the Reason at all (which seems common).   
In these cases you don't need to add the wrapper process.

I hope that helps.

Chris Bernard

On Jun 3, 2010, at 4:50 AM, Alex Arnon wrote:

> Hi,
> I am also running into a similar issue with my tests.
> I am running unit tests that spawn-link a gen_server (tests are  
> defined in
> same module), then send it a shut down request.
> The tests work on R12B5, but fail with the following on R13B1 and  
> R13B4.
> Note that the final error is different from David's:
> (emacs@REDACTED)2> eunit:test(dbr_status_server).
> dbr_status_server: server_stop_0_test...*skipped*
> undefined
> *unexpected termination of test process*
> ::shutdown
> =======================================================
>  Failed: 0.  Skipped: 0.  Passed: 1.
> One or more tests were cancelled.
> error
> A unit test that does not invoke the gen_server passes with no  
> problem (see
> 'Passed: 1' above).
> Please help! :)
> On Mon, Jun 15, 2009 at 11:37 PM, Richard Carlsson  
> <richardc@REDACTED>wrote:
>> David Mercer wrote:
>>> *unexpected termination of test process*
>>> ::{badarg,[{io,put_chars,[<0.133.0>,unicode,<<>>]},
>>>          {eunit_proc,handle_test,2},
>>>          {eunit_proc,tests_inorder,3},
>>>          {eunit_proc,with_timeout,3},
>>>          {eunit_proc,run_group,2},
>>>          {eunit_proc,child_process,2}]}
>> Are you running R13B (not R13B01) with an unpatched EUnit? In that  
>> case,
>> either install the fixed 2.1.1 version that can be found on the  
>> download
>> page (http://www.erlang.org/download.html), or upgrade to R13B01.  
>> Sorry
>> for the inconvenience.
>>   /Richard
>> ________________________________________________________________
>> erlang-questions mailing list. See http://www.erlang.org/faq.html
>> erlang-questions (at) erlang.org

More information about the erlang-questions mailing list