05.11.07

Apache vs. Yaws

Posted in Erlang at 12:04 pm by BestFriendChris

Ok. I know I already posted today, but this was just cool. A performance diagram comparing Apache to Yaws (An Erlang webserver). Apache dies at around 4,000 parallel sessions, while yaws still works at 80,000. Amazing.

EUnit vs ErUnit

Posted in ErUnit at 8:15 am by BestFriendChris

I recently was pointed to this article by pragdave about test-first development in Erlang with EUnit. I’m going to use his examples to show you how it would be done in ErUnit instead. First, some history…

The reason I wrote ErUnit instead of just using EUnit is for a couple of reasons

  1. The best way to learn a language is to reimplement xUnit. There’s so much meta stuff going on that it really requires you to dig in the language. And when I say reimplement, I don’t mean, “Follow the xUnit spec exactly.” What I mean is leverage the things that make the language good to create a good fit.
  2. I didn’t see it on the web. Mostly because I assumed EUnit was for the E programming language. So, I searched for ErUnit and found nothing…
  3. Even after I found out about EUnit, it didn’t gel with me. Now, that might be due to there not being any good tutorials that I could find, but I just wasn’t seeing it. I don’t like using macros specifically for assertions as it makes the failures hard to debug.
  4. I really don’t like having your tests live in the same file as your production code… It makes your code much harder to understand if you have to double the size of the file just to test it…
  5. I’m not a big fan of the standard that I saw of using pattern matching for the tests. I personally think there should be a difference between a failed assertion and a failed pattern match within your code, and I don’t know how to make that distinction.

A huge benefit of going with EUnit is that it is MUCH more mature than ErUnit. I’m still tweaking it as need arises. One thing that I’m not sure if it really matters yet is all tests are run in their own thread, concurrently. I did that because it seemed super easy and fun to do, but I don’t know if you really get any benefit with that yet…

Well, on to creating a word wrap utility, test first, with ErUnit.

ErUnit in >60 Seconds

When creating a ErUnit test, you first name the file starting with “test_”. In our example below, when testing “text.erl”, we create the test file “test_text.erl”. ErUnit, with erunit_suite, has the convention of either:

  • If your code and tests are in the same folder, add that folder to the path
  • If your code is in the “ebin” folder and the tests are in the “ebin_tests” folder, adding both folders to the path

This allows you to break up the tests from the code it’s testing pretty easily. Within the test class, you have to add the erunit_test behaviour. Behaviours in Erlang (well, technically the OTP library in Erlang) are used to define what callback functions are required. In this case, the erunit_test callback requires a function call “tests” with no arguments to be exported.

I personally also add a no argument “run” function that just delegates to erunit:run() with the tests passed in. I also like to import all of the erunit functions I’m going to be using (test/2, assertEquals/2, run/1) and the functions I’m going to be testing. This makes the code later on easier to read.

The file so far is:

-module(test_text).

-behaviour(erunit_test).
-export([tests/0, run/0]).

-import(erunit, [test/2, assertEquals/2, run/1]).
-import(text, [wrap/1]).

run() ->
	run(tests()).

As mentioned earlier, you must declare a no argument function called “tests”. All this returns is an array of tests. So, for the first example we want to test that the “wrap” function works with no words.

tests() ->
		[
			test("Should wrap no words", fun() ->
				assertEquals([""], wrap([]))
			end)
		].

When you use the erunit:test/2 function, you pass in the description of what you’re testing and a fun/0 of the actual test. assert(Description, true-false-test), assertEquals(First, Second), assertEquals(Description, First, Second), and fail(Description) are all currently implemented. Behind the scenes, the “test” function spawns a new thread that will run the fun/0 and send the answer back to the current test runner thread.

The code for the “text” module is the same as in pragdave’s example, so I won’t repeat it here. In fact, I’m just going to show you the entire test file:

-module(test_text).

-behaviour(erunit_test).
-export([tests/0, run/0]).

-import(erunit, [test/2, assertEquals/2, run/1]).
-import(text, [wrap/1]).

run() ->
	run(tests()).

tests() ->
		[
			test("Should wrap no words", fun() ->
				assertEquals([""], wrap([]))
			end),

			test("Should wrap one word", fun() ->
				assertEquals(["cat"], wrap(["cat"]))
			end),

			test("Should wrap two words", fun() ->
				assertEquals(["cat dog"], wrap(["cat", "dog"]))
			end),

			test("Should wrap when more than 10 chars long", fun() ->
				Expected = ["cat dog", "elk"],
				assertEquals(Expected, wrap(["cat", "dog", "elk"]))
			end),

			test("Should allow word larger than 10 on its own line", fun() ->
				Expected = ["cat dog", "hummingbird", "ibix"],
				Actual = wrap(["cat", "dog", "hummingbird", "ibix"]),
				assertEquals(Expected, Actual)
			end)
		].

The output when running from erl is:

1> test_text:run().
.....
ok
2>

When a test fails with this extra test added:

			test("This will fail", fun() ->
				erunit:fail("Called erunit:fail/1")
			end),

…you get…

1> test_text:run().
....F.
-"This will fail" failed:
        Called erunit:fail/1
fail
2>

To show an error, this is the test:

			test("This will have an error", fun() ->
				erunit:assert("This method does not work with a integer", wrap(1))
			end),

…which produces…

1> test_text:run().
....E.
-"This will have an error" had error:
        error:function_clause
                {erunit,'-test_process/3-fun-0-',3}
fail
2>

…Not the best error message, but I’m working on it. :-)

04.23.07

ErUnit - Unit Testing for Erlang

Posted in ErUnit at 10:06 pm by BestFriendChris

So, I just wrote about my new favorite language Erlang. When learning a new language, it usually helps me to work on a simple problem I’ve solved before to understand how things work. So, I grabbed one of the coding exercises we use in recruiting at t-dub (no, I’m not going to post about them). Now, as every good xp-er, I started writing my test. Or, I should say, started looking for an xUnit framework for Erlang. Nada.

So, I wrote one myself. Test-first, I might add. (Trust me, it doesn’t get much more meta than that).

Download me. (or svn co http://codeby.bestfriendchris.com/svn/ErUnit/tags/erunit-0.1.0/)

To install, put it in the Erlang code path (on my OSX machine, it is /opt/local/lib/erlang/lib). Also, if you want to use the erlang script, add the bin folder to your PATH.

To write tests, you just need to name your test file test_whatever_you_want and add the following to the file:

-behaviour(erunit_test).
-export([tests/0]).

I’d show you some more example test code, but my code highlighter doesn’t support Erlang, and I don’t really have the time to hack a new language file together for it right now. So, I’ll link directly to the test case I used in writing ErUnit: test_erunit.erl

To run tests from the command line, type:

# run all tests in the current folder
erunit
# run tests in the “tests” folder
erunit tests

To run the test from erl, type:

% run all tests in the current folder
erunit_suite:run()
% run tests in the “tests” folder
erunit_suite:run(”tests”)

A few more notes:

  • If you use seperate folders ebin and src for your .beam and .erl files respectively, ErUnit has the convention of using ebin_test and test. Again, look at the way ErUnit itself is packaged to get the idea.
  • erunit_suite will run all tests in every subfolder of the one it is run in.This allows you to have some sort of hierarchy to your code and tests.
  • erunit_suite is pretty smart about loading test files. It will make sure that all of the folders the test.beam files are in are included in the code path and auto-magically handle the case where you are using seperate ebin and ebin_test folders. Subfolders within either ebin or ebin_test are not yet supported.
  • You might notice that a bunch of the features of most other xUnit implementations are missing. This is, at least in some cases, on purpose (in others, it’s because we’re talking 0.1 version). I’m only adding features as I need them. For instance, I haven’t added Setup or Teardown methods, mostly because I’m not yet convinced that they will be required in a functional language. And even if they are needed, it’s pretty trivial to wrap your test functions in a setup/teardown pair of funs.
  • No Documentation? Yeah. I’ve actually been sitting on ErUnit for at least a week because I wanted to write some good docs for it. Since that hasn’t happened yet, I figured I’d at least put this out there and maybe get around to it eventually.

Comments/Suggestions/Complaints?

Erlang - Good fun (groan)

Posted in Erlang at 9:01 pm by BestFriendChris

So, the other day I was shopping around for a new language. Specifically, I was looking for a functional language that wouldn’t cause my brain to bleed (and not Scheme. Love it dearly, but I needed something new). Enter Erlang. I found out about this little guy from a new beta book from the prag guys called Programming Erlang, Software for a Concurrent World (totally recommend it).

Bullets:

  • Functional
    No state == Hooray!

  • Supports Hot Swapping of code
    I know I wouldn’t even think of swapping any other way than hot

  • Designed to support distributed, fault-tolerant, soft-real-time, non-stop applications
    I actually know what that means! To be fair, I swiped that bullet off the wikipedia page

  • Super Sweet Thread Communication Mechanism(tm)
    Threads are actually an extremely common part of Erlang development. In most languages, threads hurt kittens. In Erlang, they only hurt nasty dogs who probably deserved it.

I’d recommend checking out the prag book linked above and see for your self. In a bit I’m going to post about ErUnit, the xUnit testing framework I wrote for Erlang. In the mean time, here’s my initial stab at a TextMate Erlang bundle.