[erlang-questions] Question about foreach in Eunit

Richard Carlsson <>
Thu Nov 20 20:03:07 CET 2008


Josh Kuhn wrote:
> Hi,
> 
> I'm new to eunit and I am trying to get a certain group of tests
> completed that require a setup and teardown. Specifically, I have an ets
> table that I would like to set up and then drop after each small test.
> The problem is, the eunit macro for this seems to be only performing the
> setup and teardown at the beginning of the series and at the end. I am
> using a "foreach", but it is acting like a "setup".  I have some code
> below to illustrate what I am talking about:
> 
> db_functions_test_() ->
>     {foreach,
>      fun()->
>              {ets:new(usertable,[set,public]),
>               ets:new(addrtable,[set,public])}
>      end,
>      fun({Users,Addrs})->
>              ets:delete(Users),
>              ets:delete(Addrs)
>      end,
>      [fun db_test_list_/1]
>     }.
> 
> db_test_list_(Tables) ->
>     [{"Add user to empty table",
>      
> ?_assertMatch(user_added,fastrets:add_user(Tables,"Test",{'localhost',4000}))},
>      { ,
> <*Lots more tests here -snip-*>

This is because the "body" contains only a single item (the instantiator
fun db_test_list_/1). And if you think some more about it, you'll see
that you have actually abstracted the entire list of tests in
db_test_list_(Tables) over the _same_ value of Tables, i.e., there
is no way you can get to that list without giving it a value for Tables,
and then it will be the same for all of them.

If you want to run each subtest separately for different Tables, you'll
have to write each one so that it is individually parameterized, for
example by writing them as 1-ary "abstract" test functions:

db_test_add_to_empty(Tables) ->

?assertMatch(user_added,fastrets:add_user(Tables,"Test",{'localhost',4000})).

db_test_get_all_from_empty(Tables) ->
  ?assertMatch([],fastrets:get_all_users(Tables)).

(etc.), and to use these abstract tests, replace the body [fun
db_test_list_/1] with this:

  {with, [db_test_add_to_empty/1, db_test_get_all_from_empty/1, ...]}

or, you can inline the list of subtests as the body, but wrap each of
them in a 1-ary anonymous instantiator fun:

 [fun (Tables) ->
    {"Add user to empty table",
     ?_assertMatch(user_added,
                   fastrets:add_user(Tables,"Test",{'localhost',4000}))}
  end,
  fun (Tables) ->
    {"Get all users from empty table",
     ?_assertMatch([],fastrets:get_all_users(Tables))}
  end,
  ...]

(Or you can write named functions for the instantiators, if you want
to make them reusable.)

Sometimes the hard part of setting up tests like this is figuring
out what needs to be parameterized over what.

    /Richard



More information about the erlang-questions mailing list