1

When writing tests I find myself writing all kinds of small little helper functions to make assertions. I searched for an assertion library and didn't find anything. In my tests I often have things like this:

value_in_list(_Value, []) ->
  false;
value_in_list(Value, [Item|List]) ->
  case Value == Item of
    true ->
      true;
    false ->
      value_in_list(Value, List)
  end.

test_start_link(_Config) ->
  % should return the pid and register the process as my_app
  {ok, Pid} = my_app:start_link(),
  true = is_pid(Pid),
  value_in_list(my_app, registered()).

I end up having to write a whole function to check if my_app is a registered process. It would be much nicer if I could just call something like assertion:value_in_list(my_app, registered()) or assertion:is_registered(my_app).

I come from a Ruby background so I hate having to clutter up my tests with utility functions just to make a few assertions. It would be much cleaner if I could just do:

test_start_link(_Config) ->
  % should return the pid and register the process as my_app
  {ok, Pid} = my_app:start_link(),
  true = is_pid(Pid),
  assertion:value_in_list(my_app, registered()).

So my questions are:

  • Why doesn't an assertion library exist for Common Test?
  • Would it be possible to build a third party library that would be accessible during all tests?
Stratus3D
  • 4,648
  • 4
  • 35
  • 67
  • Not related to Common Test, but I would say you should be using EUnit if you want to make assertions regardless. EUnit provides plenty of assertion macros (though the is_registered case would not be included; instead you'd have to do something like `?assert(lists:member(my_app, registered())`) – Soup d'Campbells Jul 03 '14 at 19:58
  • Also, take a look at Berzemus' answer (and the link to LYSE) here, as it explains the different use-cases for EUnit and Common Test quite well: http://stackoverflow.com/questions/18031247/eunit-vs-common-test – Soup d'Campbells Jul 03 '14 at 20:03
  • Perhaps I misused the word assertion. I simply mean that an exception is raised when something returns an unexpected value. For example, in the code I have above, I would consider `true = is_pid(Pid)` to be an assertion. If `Pid` is not a pid an exception will be raised. – Stratus3D Jul 03 '14 at 20:25
  • Actually, thinking more about this, there is no need to test this. The standard OTP tests should make sure this happens as expected. – I GIVE CRAP ANSWERS Jul 04 '14 at 12:01
  • This was probably a poor choice of an example. There is no need to test that the process gets registered. I was trying to illustrate the fact that often times we need to clutter our tests with helper functions to determine if the function we are testing is working the way we expect it to. – Stratus3D Jul 07 '14 at 13:41

4 Answers4

1

Some ideas for this:

Move your application startup to the suite's startup section:

init_per_suite(Config) ->
  {ok, Pid} = my_app:start_link(),
  true = is_pid(Pid),
  [{app, Pid} | Config].

Then write your test registration as:

test_registration(Config) ->
  Pid = ?config(app, Config),
  true = lists:member(Pid, registered()).

There is no need to assert things via explicit assertion functions since they are "built in". Just make a failing match like above and the test process will crash. And hence report that the test case went wrong. Each test case is run in its own process. Which is also why you want to start the application in the init_per_suite/1 callback. Otherwise, my_app will be terminated once your test case has run since you are linked to the process-per-test-case.

So the answer is: assertions are built in. Hence there is less need for an assertion library as such.

I GIVE CRAP ANSWERS
  • 18,739
  • 3
  • 42
  • 47
1

On a side note, it's terser and more efficient to write that first block in pattern matching in the signature, rather than to add a case.

value_in_list(_Value, []           ) -> false;
value_in_list( Value, [Value|List] ) -> true;
value_in_list( Value, [ _   |List] ) -> value_in_list(Value, List).

I realize this should probably just be a comment to the original question, but that's murderously difficult to read without monospace and newlines.

John Haugeland
  • 9,230
  • 3
  • 37
  • 40
  • 3
    This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. – rgettman Aug 12 '14 at 22:02
  • kay, sorry, i pretty much don't use stack overflow and i don't know the local rules very well. in this language it's a major performance difference. i was just trying to give him a helpful hint. – John Haugeland Aug 12 '14 at 23:38
1

You can just use EUnit assertions in Common Test.

-include_lib("eunit/include/eunit.hrl").

And all the regular assertions are available.

I GIVE TERRIBLE ADVICE
  • 9,578
  • 2
  • 32
  • 40
1

I decided to write an Erlang assertion library to help with cases like this. It provides this functionality.

Stratus3D
  • 4,648
  • 4
  • 35
  • 67