Using Rake for Erlang Unit Testing
21st Century Code WorksBest of Erlang - noreply@blogger.com (Benjamin Nortier) - April 02, 2008My previous Erlang/Yaws project, dayfindr.com, is ticking along nicely:
$ yaws --status --id dayfindrThe feedback has been mostly positive, although I’ve had a “That’s a very irritating site.” comment. Well, you can’t please everyone!
Uptime: 33 Days, 13 Hours, 38 Minutes
Following on the experience gained with dayfindr, I’m starting a new Lyme project which will be using some of the OTP design principles (Think of OTP as Erlang application design patterns). Using OTP will give me hot upgrades, which dayfindr lacks at the moment. The first step that I encountered towards this goal was getting my directory structure to conform to the OTP application structure:
/project [The project root]
/ebin [The compiled .beam files]
/src [The source .erl files]
/include [Include files like record definitions]
I’ve been using the Makefile that’s provided in the Erlang book
Building Erlang with Rake
When they make a movie of my life and this moment, you will hear an orchestra and a choir of baritones singing “Eureka” when I click on the link.
Rake is an Ruby equivalent of Make, and more. It took some effort to get it working, since I had rake 0.7.1 on my machine, but trying to find the problem taught me a bit of Ruby in the process. Upgrading to 0.7.3 solved the problem. Sean’s Rakefile compiles your src files into the ebin directory very nicely! After tinkering around with Rake, I realised that it’s a really nice tool:
- It has a nice mix of declarative and imperative code. You can define rules (e.g. always compile .erl to .beam), or tasks (which can be imperative, e.g. running unit tests).
- You can use the full power of Ruby, and don’t need to learn Make.
- It has syntax that is very close to the domain (i.e. it’s a good DSL)
- It’s easy to debug, since you can use the normal Ruby puts functions etc.
- How you set up you dependencies is completely up to you, e.g. you can have different rules for files that conform to different regular expressions.
In order to get this going I created two Erlang files, foo.erl and bar.erl. Here’s bar.erl, which contains two functions, and a test (EUnit)for each function. One of the tests will fail:
Notice that the unit test code is only compiled into the beam file when the EUNIT flag is set. You can set this in the Rakefile. The unit tests are in the same source file, so we can also test non-exported functions.
-module(bar).
-export([bar1/0, bar2/0]).
-ifdef(EUNIT).
-include_lib("eunit/include/eunit.hrl").
-endif.
bar1() ->
ok.
bar2() ->
okk.
-ifdef(EUNIT).
bar1_test_() ->
[
?_assert(ok == bar1())
].
-endif.
-ifdef(EUNIT).
bar2_test_() ->
[
?_assert(ok == bar2())
].
-endif.
Now let’s look at the Rakefile:
The juicy bits are the rule and the “run_tests” task. The rule states “for each file ending in .erl, compile the beam file using erlc and put the beam file in ebin”. The run_tests task starts up an erlang runtime for each module, and calls test() for that module. The test output is captured and parsed using regular expressions. I know the Ruby code can be improved, so comments are most welcome.
require 'rake/clean'
INCLUDE = "include"
ERLC_FLAGS = "-I#{INCLUDE} +warn_unused_vars +warn_unused_import"
SRC = FileList['src/*.erl']
OBJ = SRC.pathmap("%{src,ebin}X.beam")
CLEAN.include("ebin/*.beam")
directory 'ebin'
rule ".beam" => ["%{ebin,src}X.erl"] do |t|
sh "erlc -D EUNIT -pa ebin -W #{ERLC_FLAGS} -o ebin #{t.source}"
end
task :compile => ['ebin'] + OBJ
task :default => :compile
task :run_tests => [:compile] do
puts "Modules under test:"
OBJ.each do |obj|
obj[%r{.*/(.*).beam}]
mod = $1
test_output = `erl -pa ebin -run #{mod} test -run init stop`
if /*failed*/ =~ test_output
test_output[/(Failed.*Aborted.*Skipped.*Succeeded.*$)/]
else
test_output[/1>s*(.*)n/]
end
puts "#{mod}: #{$1}"
end
end
Here’s what happens when I compile and run the tests:
At this points I have cleaning, compiling and running the tests for each module. Nice. I’m quite pleased with how it works at the moment, but there’s still quite a bit of work to be done:
$ rake clean
(in /home/bjnortier/development/project1)
$ rake
(in /home/bjnortier/development/project1)
erlc -D EUNIT -pa ebin -W -Iinclude +warn_unused_vars +warn_unused_import -o ebin src/foo.erl
erlc -D EUNIT -pa ebin -W -Iinclude +warn_unused_vars +warn_unused_import -o ebin src/bar.erl
$rake run_tests
(in /home/bjnortier/development/project1)
Modules under test:
foo: All 2 tests successful.
bar: Failed: 1. Aborted: 0. Skipped: 0. Succeeded: 1.
- Concatenating the running of the unit tests into one no-shell erlang execution. Actually running the tests are very fast, but the shell termination takes about a second or so. Thus, for each module, there is a approximately a second of extra time. Running all the tests in the same erlang session will require some more text parsing, but it’s do-able.
- Displaying the failed tests. Seeing “Failed: 1” is not very useful for determining what went wrong, so I’ll update the parsing to include the failures and errors.
- Probably change the “run_tests” task to just “test”
- Continuous integration that hooks into version control.
If there is significant progress I’ll post the results. I hope you can use some of it :)
Categories: Blogs 21st Century Code Works Best of Erlang
Comments
No comments so far, you could be the first.Add comment
Erlang on Twitter
» michelir5 (Micheli Gelatinous): @pharkmillups Still seeing it. I might just have to manually install it. The version of Erlang required by Riak is not current version in HB
» Angry_Lawyer (Tony Aldridge): @rvirding @saghul If Erlang kills you, does a supervisor automatically create a replacement of you?
» rvirding (Robert Virding): Softly I hope. RT @saghul: Slowly making progress… erlang is killing me.
» jsvd (João Duarte): RT @FrancescoC: Woot! RT @valdo404: Practical Erlang Programming at #QConLondon I want to go there
» saghul (Saúl Ibarra Corretgé): Slowly making progress… erlang is killing me.
» dlsspy (Dustin Sallings): @IbnFirnas heh. The erlang parts are still solid. The currently active alerting box is arm5, failed over from a pc that died one day.
» quercialwji2 (Quercia Quinn): @MikeSmooth_ABCs http://t.co/pPiIpTCx
» levicole (Levi Kennedy): @pharkmillups the homebrew version of erlang is the most recent version, and riak requires R14B I think.
» Mgnadya (Mega Nadya Rustanti): WooooRT @erlangtriaji: Maap bude salah liat ._. RT @Mgnadya: Elaaaang bukan erlang -_- RT @erlangtriaji: sama” RT… http://t.co/O0DxJgAr
» levicole (Levi Kennedy): @pharkmillups Still seeing it. I might just have to manually install it. The version of Erlang required by Riak is not current version in HB
Statistics
Number of aggregated posts: 10456
Number of comments: 1445
Most recent article: February 06, 2012
Latest comments
» simple smile on Scale means Skills: Very informative article. Pretty sure people would love to go to that place for shopping. Specially to those who are…
» simplesmile on 27 January 2012: Erlang Solutions embarks on an Erlang Embedded KTP: Your article will make the world better. Thanks again and good luck to you in your life. See you next time.simplesmile
» tandblekning easewhite on 08 February 2012: Erlang Express 3-day Course in San Francisco on 8 February: ncomprehensible to me now, but in general, the usefulness and significance is overwhelmingtandblekning easewhite