Now and then, people ask me EUnit questions, and sometimes the problems consist of less obvious nuts and bolts. So, let’s explore some special and yet common errors.
For the purpose of this post, I will be using my previously seen numberserver (reposted here for your convenience).
%%% @author Gianfranco <zenon@zen.home> %%% @copyright (C) 2010, Gianfranco %%% Created : 4 Oct 2010 by Gianfranco <zenon@zen.home> -module(numberserver). -export([start/0,stop/0,op/2,get/0,init/0]). start() -> Pid = spawn_link(?MODULE,init,[]), register(?MODULE,Pid), ok. stop() -> ?MODULE ! stop, unregister(?MODULE). op(Op,Num) -> ?MODULE ! {Op,Num}, ok. get() -> ?MODULE ! {get_result,self()}, receive X -> X end. init() -> loop(basic). loop(E) -> receive stop -> ok; {get_result,From} -> From ! E, loop(E); {Op,Num} -> loop(result(Op,E,Num)) end. result(_,basic,X) -> X; result('+',X,Y) -> X + Y; result('*',X,Y) -> X * Y; result('-',X,Y) -> X - Y; result('/',X,Y) -> X / Y.
Enough with the reminiscence.
*** test module not found *** ::ok
This one is very special, and also very common. People sometimes forget that Instantiators (remember, instantiators are functions that take the setup/0 result as input argument, and returns a TestSet or Simple Test Object) must return TestSet or Simple Test Object. Classic erroneous code follows.
example_a_test_() -> {setup, fun() -> numberserver:start() end, fun(_) -> numberserver:stop() end, % Using instantiator, not returning: Test xor Simple Test Object! fun(_) -> numberserver:op('+',1), ?assertEqual(1,numberserver:get()) end }.
and the reduced error output for this
1> ======================== EUnit ======================== module 'numberserver' module 'numberserver_tests' undefined *** test module not found *** ::ok ======================================================= Failed: 0. Skipped: 0. Passed: 0. One or more tests were cancelled.
This error often (most understandably!) confuses people as it does not say: bad test descriptor or something more helpful. The correct code could have been written as
example_a_test_() -> {setup, fun() -> numberserver:start() end, fun(_) -> numberserver:stop() end, fun(_) -> fun() -> numberserver:op('+',1), ?assertEqual(1,numberserver:get()) end end }.
Test passed. (yet it’s wrong!)
Sometimes people use {setup,….}, {foreach,…} or any other fixture inside a _test() [simple test function] instead of a _test_() [test-generating function]. EUnit will then seem to execute the test, but does not do it. Proof follows below, with a faulty test-case and the output.
-module(numberserver_tests). -include_lib("eunit/include/eunit.hrl"). example_b_test() -> {setup, fun() -> numberserver:start() end, fun(_) -> numberserver:stop() end, fun() -> numberserver:op('+',3), numberserver:op('*',4), ?assertMatch(13,numberserver:get()) end}.
And the console, deceives us with
zen:EUnitProblems zenon$ erlc -o ebin/ src/*.erl test/*.erl zen:EUnitProblems zenon$ erl -pa ebin/ -eval 'eunit:test(numberserver,[verbose]).' Erlang R13B04 (erts-5.7.5) [source] [64-bit] [smp:4:4] [rq:4] [async-threads:0] [hipe] [kernel-poll:false] Eshell V5.7.5 (abort with ^G) 1> ======================== EUnit ======================== module 'numberserver' numberserver_tests: example_b_test (module 'numberserver_tests')...ok [done in 0.002 s] ======================================================= Test passed. 1>
This shows us how IMPORTANT, it is to ALWAYS have a failing test first. If we would have a failing test first, because it’s obvious that it’s failing, this type of errors can not sneak onto us.
Correct code would have been
-module(numberserver_tests). -include_lib("eunit/include/eunit.hrl"). example_b_test_() -> {setup, fun() -> numberserver:start() end, fun(_) -> numberserver:stop() end, fun() -> numberserver:op('+',3), numberserver:op('*',4), ?assertMatch(13,numberserver:get()) end}.
and console output
zen:EUnitProblems zenon$ erlc -o ebin/ src/*.erl test/*.erl zen:EUnitProblems zenon$ erl -pa ebin/ -eval 'eunit:test(numberserver,[verbose]).' Erlang R13B04 (erts-5.7.5) [source] [64-bit] [smp:4:4] [rq:4] [async-threads:0] [hipe] [kernel-poll:false] Eshell V5.7.5 (abort with ^G) 1> ======================== EUnit ======================== module 'numberserver' module 'numberserver_tests' numberserver_tests: example_b_test_...*failed* ::error:{assertMatch_failed,[{module,numberserver_tests}, {line,11}, {expression,"numberserver : get ( )"}, {expected,"13"}, {value,12}]} in function numberserver_tests:'-example_b_test_/0-fun-2-'/0 [done in 0.003 s] [done in 0.003 s] ======================================================= Failed: 1. Skipped: 0. Passed: 0.
This post will be updated as time goes and people ask questions, etc. So check it out once in a while!
Cheers
/G