I have been trying to export all the functions in an erlang module for use in a common test SUITE, not an eunit module. So far it has not worked for me. I am using rebar to run the SUITE, and I came across this question (http://lists.basho.com/pipermail/rebar_lists.basho.com/2011-October/001141.html), which is essentially exactly what I want to do, but the method will not work for me.
I have also added {plugins, [rebar_ct]}. into rebar.config but it has made no difference. I should point out all my tests pass when I export the functions normally, but I want to avoid this.
Any help would be great thanks.
The compiler will cause all functions in a module to be exported if you add this into it:
-compile(export_all).
Or you could do it based on defs, like:
-ifdef(EXPORTALL).
-compile(export_all).
-endif.
That will only export everything if you have {d, 'EXPORTALL', true} in your rebar config erl_opts setting, e.g. something like:
{erl_opts, [
{d, 'EXPORTALL', true}
]}.
If that doesn't work, make sure you don't have erl_opts twice in your rebar config.
with rebar3 you can define in the config file extra option for the compilation for common test:
{ct_compile_opts, []}.
her you can add export_all which will be available for common test only. not sure it exists for rebar.
Related
I'm going through the EUnit chapter in Learn You Some Erlang and one thing I am noticing from all the code samples is the test functions are never declared in -export() clauses.
Why is EUnit able to pick these test functions up?
From the documentation:
The simplest way to use EUnit in an Erlang module is to add the following line at the beginning of the module (after the -module declaration, but before any function definitions):
-include_lib("eunit/include/eunit.hrl").
This will have the following effect:
Creates an exported function test() (unless testing is turned off, and the module does not already contain a test() function), that can be used to run all the unit tests defined in the module
Causes all functions whose names match ..._test() or ..._test_() to be automatically exported from the module (unless testing is turned off, or the EUNIT_NOAUTO macro is defined)
Glad I found this question because it gives me a meaningful way to procrastinate and I was wondering how functions get created and exported dynamically.
Started by looking at the latest commit affecting EUnit in the Erlang/OTP Github repo, which is 4273cbd. (The only reason for this was to find a relatively stable anchor instead of git branches.)
0. Include EUnit's header file
According EUnit's User's Guide, the first step is to -include_lib("eunit/include/eunit.hrl"). in the tested module, so I assume this is where the magic happens.
1. otp/lib/eunit/include/eunit.hrl (lines 79 - 91)
%% Parse transforms for automatic exporting/stripping of test functions.
%% (Note that although automatic stripping is convenient, it will make
%% the code dependent on this header file and the eunit_striptests
%% module for compilation, even when testing is switched off! Using
%% -ifdef(EUNIT) around all test code makes the program more portable.)
-ifndef(EUNIT_NOAUTO).
-ifndef(NOTEST).
-compile({parse_transform, eunit_autoexport}).
-else.
-compile({parse_transform, eunit_striptests}).
-endif.
-endif.
1.1 What does -compile({parse_transform, eunit_autoexport}). mean?
From the Erlang Reference Manual's Module chapter (Pre-Defined Module Attributes):
-compile(Options).
Compiler options. Options is a single option or a list of options. This attribute is added to the option list when
compiling the module. See the compile(3) manual page in Compiler.
On to compile(3):
{parse_transform,Module}
Causes the parse transformation function
Module:parse_transform/2 to be applied to the parsed code before the
code is checked for errors.
From the erl_id_trans module:
This module performs an identity parse transformation of Erlang code.
It is included as an example for users who wants to write their own
parse transformers. If option {parse_transform,Module} is passed to
the compiler, a user-written function parse_transform/2 is called by
the compiler before the code is checked for errors.
Basically, if module M includes the {parse_transform, Module} compile option, then all of M's functions and attributes can be iterated through using your implementation of Module:parse_transform/2. Its first argument is Forms, which is M's module declaration described in Erlang's abstract format (described in Erlang Run-Time System Application (ERTS) User's Guide.
2. otp/lib/eunit/src/eunit_autoexport.erl
This module only exports parse_transfrom/2 to satisfy {parse_transform, Module} compile option and its first order of business is to figure out what are the configured suffixes for test case functions and generators. If not set manually, using _test and _test_ respectively (via lib/eunit/src/eunit_internal.hrl).
It then scans all the functions and attributes of your module using eunit_autoexport:form/5, and builds a list of to be exported functions where the suffixes above match (plus the original functions. I may be wrong on this one...).
Finally, eunit_autoexport:rewrite/2 builds a module declaration from the original Forms (given to eunit_autoexport:parse_transform/2 as the first argument) and the list of functions to be exported (that was supplied by form/5 above). On line 82 it injects the test/0 function mentioned in the EUnit documentation.
I'm using rebar to compile my application. Actually, it's two applications:
deps/
apps/A/
apps/B/
apps/B/suites
...where B depends on A. This is correctly configured in apps/B/src/B.app.src. However, when I attempt to run rebar ct, it fails to test B, reporting that it can't find A.app.
Running rebar ct in verbose mode shows that it's setting the code search path (-pa) to include apps/B/ebin, and deps/foo/ebin, deps/bar/ebin, etc.
It is not including apps/A/ebin.
How do I use Common Test to test an Erlang "application" that's made up of multiple applications?
Add in apps/B/rebar.config
{lib_dirs, [
".."
]}.
or
{ct_extra_params, "-pa ../A/ebin"}.
IMO, if B depends on A, I would have two separate tests. One for A and mention it deps section of B of rebar config and write separate test cases for B and run only for B so that application A modules would be automatically taken care by rebar.
This should be simple, although I could not find a way or example yet...
The Mnesia documentation shows how to initialize/create an Mnesia database from the erlang shell, which requires to start the erl shell with the -mnesia parameter:
erl -mnesia dir '"/tmp/funky"'
Once in the shell you can create the schema/etc...
>mnesia:create_schema([node()]).
ok.
>mnesia:start().
ok.
Well, that's simple enough. What if I want to create the schema/etc from another erlang module and I did not start the process with the -mnesia parateter/flag ? I think that basically means, how to dynamically, without running a script but from a pure erlang code approach. For instance, I'd like to do something like this:
-module(something).
-export([test/0]).
test() ->
erlang:setParameter("mnesia","/tmp/funcky"),
mnesia:create_schema([node()]),
...
Well, I think I found the solution. set_env is what I needed:
application:set_env(mnesia, dir, "/tmp/funcky"),
mnesia:create_schema([node()]),
etc...
I am working with Erlang and EUnit to do unit tests, and I would like to write a test runner to automate the running of my unit tests. The problem is that eunit:test/1 seems to only return "error" or "ok" and not a list of tests and what they returned in terms of what passed or failed.
So is there a way to run tests and get back some form of a data structure of what tests ran and their pass/fail state?
If you are using rebar you don't have to implement your own runner. You can simply run:
rebar eunit
Rebar will compile and run all tests in the test directory (as well as eunit tests inside your modules). Furthermore, rebar allows you set the same options in the rebar.config as in the shell:
{eunit_opts, [verbose, {report,{eunit_surefire,[{dir,"."}]}}]}.
You can use these options also in the shell:
> eunit:test([foo], [verbose, {report,{eunit_surefire,[{dir,"."}]}}]).
See also documentation for verbose option and structured report.
An alternative option would be to use Common Test instead of Eunit. Common Test comes with a runner (ct_run command) and gives you more flexibility in your test setup but is also a little more complex to use. Common Test lacks on the available macros but produces very comprehensible html reports.
No easy or documented way, but there are currently two ways you can do this. One is to give the option 'event_log' when you run the tests:
eunit:test(my_module, [event_log])
(this is undocumented and was really only meant for debugging). The resulting file "eunit-events.log" is a text file that can be read by Erlang using file:consult(Filename).
The more powerful way (and not really all that difficult) is to implement a custom event listener and give it as an option to eunit:
eunit:test(my_module, [{report, my_listener_module}])
This isn't documented yet, but it ought to be. A listener module implements the eunit_listener behaviour (see src/eunit_listener.erl). There are only five callback functions to implement. Look at src/eunit_tty.erl and src/eunit_surefire.erl for examples.
I've just pushed to GitHub a very trivial listener, which stores the EUnit results in a DETS table. This can be useful, if you need to further process those data, since they're stored as Erlang terms in the DETS table.
https://github.com/prof3ta/eunit_terms
Example of usage:
> eunit:test([fact_test], [{report,{eunit_terms,[]}}]).
All 3 tests passed.
ok
> {ok, Ref} = dets:open_file(results).
{ok,#Ref<0.0.0.114>}
> dets:lookup(Ref, testsuite).
[{testsuite,<<"module 'fact_test'">>,8,<<>>,3,0,0,0,
[{testcase,{fact_test,fact_zero_test,0,0},[],ok,0,<<>>},
{testcase,{fact_test,fact_neg_test,0,0},[],ok,0,<<>>},
{testcase,{fact_test,fact_pos_test,0,0},[],ok,0,<<>>}]}]
Hope this helps.
The include directive is usually used for a .hrl file at the top of an .erl file.
But, I would like to use include from the Erlang console directly.
I am trying to use some functions in a module. I have compiled the erl file from the console. But, the functions I want to use do not work without access to the hrl file.
Any suggestions?
"But, the functions I want to use do not work without access to the hrl file."
This can't be true, but from this I'll take a shot at guessing that you want access to records in the hrl file that you don't (normally) have in the shell.
If you do rr(MODULE) you will load all records defined in MODULE(including those defined in an include file included by MODULE).
Then you can do everything you need to from the shell.
(Another thing you may possibly want for testing is to add the line -compile(export_all) to your erl file. Ugly, but good sometimes for testing.)
Have you tried the compile:file option? You can pass a list of modules to be included thus:
compile:file("myfile.erl", [{i, "/path/1/"}, {i, "/path/2/"}])
It's worth nothing that jsonerl.hrl doesn't contain any functions. It contains macros. As far as I know, macros are a compile-time-only construct in Erlang.
The easiest way to make them available would be to create a .erl file yourself that actually declares functions that are implemented in terms of the macro. Maybe something like this:
-module(jsonerl_helpers).
-include("jsonerl.hrl").
record_to_struct_f(RecordName, Record) ->
?record_to_struct(RecordName, Record).
... which, after you compile, you could call as:
jsonerl_helpers:record_to_struct_f(RecordName, Record)
I don't know why the author chose to implement those as macros; it seems odd, but I'm sure he had his reasons.