6

I'm writing EUnit tests for Erlang code.

I have a source module:

-module(prob_list).
-export([intersection/2,union/2]).

probability([], _Item) -> false;
probability([{First,Probability}|Rest], Item) ->
    if
        First == Item -> Probability;
        true          -> probability(Rest, Item)
    end.
...
...
...

and a unit-test module:

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

-define(TEST_LIST,[{3,0.2},{4,0.6},{5,1.0},{6,0.5}]).
-define(TEST_LIST1,[{2,0.9},{3,0.6},{6,0.1},{8,0.5}]).
-define(TEST_UNO_LIST,[{2,0.5}]).

probability_test() -> ?assertNot(prob_list:probability([],3)),
                      ?assertEqual(0.5,prob_list:probability(?TEST_UNO_LIST,2)),
                      ?assertNot(prob_list:probability(?TEST_UNO_LIST,3)),
                      ?assertEqual(0.2,prob_list:probability(?TEST_LIST,3)),
                      ?assertEqual(1.0,prob_list:probability(?TEST_LIST,5)),
                      ?assertNot(prob_list:probability(?TEST_LIST,7)).
...
...
...

When I run eunit:test(prob_list,[verbose]) it says:

 prob_list_tests: probability_test...*failed*
::undef

but when I export probability/2 in my prob_list module, everything is ok.

Is there any way to test private functions?

Uko
  • 13,134
  • 6
  • 58
  • 106

3 Answers3

6

You can use the directive -compile(export_all) to conditionally export all functions only when compiling for testing:

%% Export all functions for unit tests
-ifdef(TEST).
-compile(export_all).
-endif.
Phil Calvin
  • 5,077
  • 2
  • 41
  • 35
6

The general approach that I use for this is to include all of the unit tests in the same file and the separate them out:

-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.

%% Functions
[...]


-ifdef(TEST).
%% Unit tests go here.
-endif.

This should allow you to test your private functions alongside your public functions.

David H. Clements
  • 3,590
  • 2
  • 24
  • 26
  • I've done everything that you've wrote, but I get the same result. I run `erlc -DTEST *.erl` to compile and I still get ::undef from private functions. – Uko Nov 13 '11 at 09:35
  • Ok, my fault, I've forgot to remove module name from function call within tests. – Uko Nov 13 '11 at 09:44
  • This makes it very difficult to keep erlang files crisp and readable. It is always advised to to keep test cases in separate files and take the approach suggested by Phil. – Trisha Chatterjee Mar 28 '20 at 07:59
3

Ok, so here it goes:

dclements gave me a nice hint of how can I accomplish what I've asked. I don't want to put all my tests in source module, you can see a nice example of keeping the apart here: Erlang EUnit – introduction

Now my solution is to export all functions on TEST compilation. So you put:

-define(NOTEST, true).

-export([intersection/2,union/2]).
-ifdef(TEST).
-export([intersection/2,union/2,contains/2,probability/2,lesslist/2]).
-endif.

And then compile with erlc -DTEST *.erl to run tests, and ordinary compile to export only needed functions.

Uko
  • 13,134
  • 6
  • 58
  • 106
  • 1
    That's a reasonable approach (though it is worth noting you can have multiple export lines, which may clean things up a bit), especially if you want to both separate out your unit tests into separate files and test your private functions. The one downside to this approach is that this can lead to code that passes test but won't run otherwise if you accidentally use the private methods outside of your test files. – David H. Clements Nov 14 '11 at 15:41
  • 1
    To expose everything to the test module you could use "-compile(export_all)." instead of maintaining a big export statement. – goertzenator May 30 '13 at 14:48