What are EUnit test generators?

692 views Asked by At

I have read the documentation about EUnit, but still I have no idea what is the purpose of test generators.

I have also read a nice tutorial here, but still no luck (a little too advanced).

I somewhat understand that a test generator function returns a set of tests which are then executed by EUnit. (is that right?)

Unfortunately, the only thing that I am confident about now is that I can write a test like this:

myfun_test() ->
assertEqual(myresult,mymod:myfun()).

The question is: What are the test generators in EUnit needed for and what is their relation with a Simple Test Object?

P.S. I know there is a wonderful world (example) of unit tests which are made with the help of various automation tools and concepts, but I do not know how to enter it.

2

There are 2 answers

0
Roberto Aloi On

Reading from the very page you've linked in your question:

A drawback of simple test functions is that you must write a separate function (with a separate name) for each test case. A more compact way of writing tests (and much more flexible, as we shall see), is to write functions that return tests, instead of being tests.

A function with a name ending in ...test() (note the final underscore) is recognized by EUnit as a test generator function. Test generators return a representation of a set of tests to be executed by EUnit.

Think to test generators as to the possibility of grouping tests. Apart from having more compact code, you can have advanced features for your tests. For example, a state for your set of tests, an initialization function, and so on and so forth.

If what you need for your application is just a set of assertions, well, you probably don't need test sets. You could even avoid using EUnit as a whole. The pattern matching (=) operator in Erlang is a brilliant testing operator in itself. Compare:

assertEqual(myresult,mymod:myfun()).

with:

myresult = mymod:myfun()
0
Chen Yu On

I think if you have tried to write some many unit tests for your project, you will find the value of test generator in the practice.

If use test generator, you don't need to spend time just for creation of many and many different test function names, and codes for creation of test generator is shorter than standard function.

For example, the following codes is from gproc open source project for test generator, and it uses test generator for your reference and the file can be found in github.

reg_test_() ->
    {setup,
     fun() ->
             application:start(gproc),
         application:start(mnesia)
     end,
     fun(_) ->
             application:stop(gproc),
         application:stop(mnesia)
     end,
     [
      {spawn, ?_test(?debugVal(t_simple_reg()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_simple_counter()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_simple_aggr_counter()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_update_counters()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_simple_prop()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_await()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_await_self()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_await_crash()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_simple_mreg()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_gproc_crash()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_cancel_wait_and_register()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_give_away_to_pid()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_give_away_to_self()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_give_away_badarg()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_give_away_to_unknown()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_give_away_and_back()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_select()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_select_count()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_qlc()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_get_env()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_get_set_env()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_set_env()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_get_env_inherit()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_monitor()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_monitor_give_away()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_subscribe()))}
      , ?_test(t_is_clean())
      , {spawn, ?_test(?debugVal(t_gproc_info()))}
      , ?_test(t_is_clean())
     ]}.