We are a software consultancy based in Berlin, Germany. We deliver
high quality web apps in short timespans.

Upstream Agile GmbH

Hacking CouchDB, learning Erlang and testing in Javascript

February 01, 2009 by alex

Last week was my first Erlang gig. I paired up with Jan Lehnardt (core committer of CouchDB). Our goal was to implement a new statistics module for CouchDB within one week. Jan knew more about the CouchDB code and Erlang, I contributed my knowledge about testing and pair programming.

Integration Testing in JavaScript

Since the testing infrastructure in CouchDB left some room for improvement we decided to introduce some new concepts. The existing tests were written in JavaScript penetrating the database via its HTTP/JSON interface. The tests were really long and coarse grained which lead to a problem: When one of the tests broke it wasn’t very easy to figure out which one. We didn’t want to replace or add too much to the existing, self-made test framework so we just added a bit of sugar: BDD style specs with meaningful names:

var response_count_tests = {
  'should show the number of 404 responses': function(name) {
    // Given
    restartServer();

    // When
    CouchDB.request('GET', '/some_nonexistant_url');

    // Then
    TEquals(1, CouchDB.stats_request('httpd', 'not_found'), name);
  }
};

var all_tests = [response_count_tests, ...];

for(var i in all_tests) {
  test_group = all_tests[i];
  for(var j in test_group {
    test_group[j](j);
  }
}

The TEquals function is just our extension of an existing function T which is responsible for reporting errors when the assertion doesn’t match. By passing the name of the test spec we can now display that name along with the error message:

Error in ‘should show the number of 404 responses’: ‘CouchDB.stats_request(‘httpd’, ‘not_found’)’ should be ‘1’ but was ‘0’.

Unit Testing in Erlang

In addition to those integration tests we wanted to add some unit testing on a lower level. Turns out the only unit testing framework for Erlang seems to be EUnit, which is a very barebones (at least when you come from something like RSpec) xUnit type of tool. You define a test by appending “_test” to your function name and then you have a bunch of assert statements at your disposal. Well that’s at least something and it worked. Here is an example:

should_return_zero_if_nothing_has_been_counted_yet_test() ->
    test_setup(fun() ->
        Result = ?MODULE:get({httpd, average_request_count}),
        ?assertEqual(< <"0.00">>, Result)
    end).

We added the test_setup for starting and tearing down processes needed for our tests. Then we pass a fun with the actual test code. We got through the week pretty ok with this but I really missed a few things:

  • The test output was not red/green - ok I could live with this, at least for a while, if the output was at least formatted in a way that would allow me to spot the problems more easily. The error output of erlang seems to be a big mess in general.
  • No mocking/stubbing framework. I don't even know if this is possible at all, at least I'm now aware of any way to change the behavior of Erlang code after compilation. (would that contradict Erlang's share nothing philosophy?)
  • contexts for tests - I want to be able to group my tests, not sure how this would work in Erlang syntax as there are no nested namespaces or things you can use to group methods (except for modules, but I want something smaller and you can't nest them). You would probably end up using lists of funs or something.
  • Erlang

    I’ve

    REXML could not parse this XML/HTML: 
    <a href=""http://upstream-berlin.com/2007/07/24/programming-erlang-functional-programming/>
    read the book, I’ve watched numerous screencasts but this was my first real life project in Erlang. Many people complain about its syntax and while this isn’t the most beautiful language I’ve ever seen I have to say it’s not really a big problem. I got used to it on the first day.

    What is really powerful in Erlang is pattern matching. Instead of simply assigning a value to a variable you can always match against the structure of that data to extract parts of it:

    Data = {"Hans", "Wurst", {born, 1980, 10, 23}}.
    {FirstName, _, {born, Year, _, Day} = Data.
    

    This example lets you pull out numerous details from the tuple in a single statement. You can do the same for case statements or when overloading functions. So this pattern matching is a powerful concept seen everywhere in Erlang code. It makes the code you write pretty dense which is cool on the one hand but sometimes also makes it hard to read so you have to be careful how much you want to cram into a single line of code.

    CouchDB is built using make - which felt like 1990. I’ve never used make much myself so I’m not really qualified to talk about it but we did spend a good amount of time in our MakeFile because of some whitespace problem, and we still haven’t managed to integrate our new tests into the build process. I’d love to see something like Rake being used instead.

    All in all this have been very pleasant first steps though. Pairing up for this turned out to be a very good idea, I have learned a lot about Erlang and am eager for more now.