Thursday, 20th November 2008.

Posted on Sunday, 19th October 2008 by charpi

I worked on erl_mock in order to publish my spike around mocks in
erlang when I something interesting happened: my tests failed.

More precisely, they failed when run by the ‘future’ version of extremeforge.
After the first surprise, I find the reason. Extremeforge use 2 nodes,
the first one will find, order tests then send all code on the second
node in order to be run. Like this, extremeforge keeps the first node
totally safe if for some reasons a test module (or applicative module)
gets wrong.

As my library intends to load, unload dynamically modules the test
node is lost because it can’t find the beam files.

Conclusion: Don’t use mock, :-)

Anyway I’ll publish my library soon

Tags: , ,
Posted in Uncategorized | Comments (0)

Posted on Thursday, 9th October 2008 by charpi

In my previous post, I described a way to mock module by replacing
them. Today, I’ll post a version closer to other mock
library. Basically, I create on mock module on the fly and forward all
calls to a process. You can tell to this process how to answer for
each calls.
Here is the test :

%%% Copyright (c) 2008 Nicolas Charpentier
%%% All rights reserved.
-module(mock_test).

-export([test /0]).

test () ->
    lazy_way () ,
    dynamic_way (),
    ok.

lazy_way () ->
    "i'm the production code" = my_module: who(),
    mock: replace_module (my_module, my_mock_module),
    "I'm the mocked code" = my_module: who (),
    mock: uninstall (my_module),
    "i'm the production code" = my_module: who (),
    ok.

dynamic_way () ->
    "i'm the production code" = my_module: who (),
    {pong,host} = my_module: ping (host),

    mock: start (),
    mock: add_module(my_module),
    mock: set_answer (my_module, who, "I'm the mocked code"),
    "I'm the mocked code" = my_module: who (),
    mock: set_answer (my_module, who, "Oops did it wrong"),
    "Oops did it wrong" = my_module: who (),

    [{my_module, who, []}, {my_module, who, []}] =  mock: calls (),
    [] =  mock: calls (),

    case catch my_module: ping(host) of
        error_no_response -> ok;
        Other -> exit({unexepected_mock_response, Other})
    end,

    mock: set_answer (my_module, ping, {pang, mock_host}),
    {pang, mock_host} = my_module: ping(last_host),

    [{my_module, ping, [host]},
     {my_module, ping, [last_host]}] =  mock: calls (),

    mock: uninstall (my_module),
    "i'm the production code" = my_module: who (),
    {pong,host} = my_module: ping (host),
    ok.

and the implementation

%%% Copyright (c) 2008 Nicolas Charpentier
%%% All rights reserved.
-module(mock).

-export([replace_module /2]).
-export([uninstall /1]).

-export([start /0]).
-export([add_module /1]).
-export([set_answer /3]).
-export([calls /0]).

replace_module (Module, Mock_module) ->
    uninstall (Module),
    {ok, Binary} = file: read_file (code: which (Mock_module)),
    File_name = atom_to_list (Module) ++ ".erl",
    code: load_binary(Module, File_name, Binary),
    ok.

uninstall (Module) ->
    code: purge (Module),
    code: delete (Module).

start () ->
    Pid = spawn_link (fun () -> mocker ([],[]) end),
    register(mocker, Pid),
    ok.

add_module (Module) ->
    Forms = forms (Module),
    uninstall (Module),
    {ok, _, Binary} = compile: forms(Forms, [report]),
    code: load_binary (Module, "foo.erl", Binary),
    ok.

set_answer (Module, Function, Answer) ->
    mocker ! {set_answer, Module, Function, Answer},
    ok.

calls () ->
    mocker ! {self(), calls},
    receive
        {calls, Calls} ->
            Calls
    end.

forms (Module) ->
    Exported_functions = find_exported_functions (Module),
    Fun = fun (F) -> function_to_form (Module, F) end,
    Functions_forms = [Fun(F) || F <- Exported_functions],
    [{attribute,1,module,Module},
     {attribute,3,export,Exported_functions}] ++
        Functions_forms  ++
        [ {function,16,wait_response,0,
           [{clause,16,[],[],
             [{'receive',20,
               [{clause,20,
                 [{tuple,20,[{atom,20,response},{atom, 20, undefined}]}],
                 [],
                 [{call,20,
                   {atom,20,throw},
                   [{atom,20,error_no_response}]}]},
                {clause,20,
                 [{tuple,20,[{atom,20,response},{var,20,'Response'}]}],
                 [],
                 [{var,19,'Response'}]}
                ]}]}]},
          {eof,23}].

function_to_form (Module, {Function, Arity}) ->
    Parameters = parameters (Arity),
    Parameters_cons = parameters_cons (Arity),
    {function,5,Function,Arity,
     [{clause,5,Parameters,[],
       [{op,6,'!',
         {atom,6,mocker},
         {tuple,6,
          [{call,6,{atom,6,self},[]},
           {atom,6,forward},
           {atom,6,Module},
           {atom,6,Function},
           Parameters_cons]}},
        {call,8,{atom,8,wait_response},[]}
       ]}]}.

parameters (0) ->
    [];
parameters (N) ->
    Seq = lists: seq (1,N),
    F = fun (I) ->
                String = lists:flatten (io_lib: format ("Var~p",[I])),
                list_to_atom(String)
        end,
    [{var, 6, F(I)} || I <- Seq].

parameters_cons (N) ->
    parameter_list_form (parameters (N)).

put_parameter_in_call (Parameters) ->
    list_to_tuple (transform_list_to_cons (Parameters)).

transform_list_to_cons ([]) ->
    [nil, 6];
transform_list_to_cons ([H|T]) ->
    [cons, 6, H, put_parameter_in_call (T)].

parameter_list_form ([]) ->
    {nil,6};
parameter_list_form (Variable_forms) ->
    put_parameter_in_call (Variable_forms).

find_exported_functions (Module) ->
    Module_info = Module: module_info (),
    All_exported = proplists: get_value (exports, Module_info),
    lists: filter (fun ({module_info,_}) ->
                           false;
                       (_) ->
                           true
                   end, All_exported).

mocker (Modules, Calls) ->
    receive
        {From, calls} ->
            From ! {calls,lists: reverse (Calls)},
            mocker (Modules, []);
        {set_answer, Module, Function, Answer} ->
            New_modules = proplists: delete ({Module, Function}, Modules),
            mocker ([{{Module, Function}, Answer}|New_modules], Calls);
        {From, forward, Module, Function, Args} ->
            Response = proplists: get_value ({Module,Function}, Modules),
            From ! {response, Response},
            mocker (Modules, [{Module, Function, Args}|Calls])
    end.

Tags: ,
Posted in Uncategorized | Comments (3)

Posted on Wednesday, 8th October 2008 by charpi

In my previous post, I wrote a test to specify a lazy
mock. In my mind, a lazy mock consists to replace the implementation
of one module by another one at runtime.

Here is the implementation of the lazy mock test

-module(mock).

-export([replace_module /2]).

replace_module (Module, Mock_module) ->
    uninstall (Module),
    {ok, Binary} = file: read_file (code: which (Mock_module)),
    File_name = atom_to_list (Module) ++ ".erl",
    code: load_binary(Module, File_name, Binary),
    ok.

uninstall (Module) ->
    code: purge (Module),
    code: delete (Module).

The tricky thing is that your mock module must not be a valid
erlang beam file. The code_loader use the beam file name to locate the
code load but the VM expected that the module declaration in the file
got the same name than the file.
In order to use my implementation of the lazy mock your mock
module must have the same module declaration than the real
implementation.
Here is the content of the source file my_mock_module.erl:

-module(my_module).

-export([who /0]).

who () ->
    "I'm the mocked code".

Tags: ,
Posted in Uncategorized | Comments (0)

Posted on Friday, 3rd October 2008 by charpi

People coming from object oriented programming often use mock
object
in their unittest. The main question is do we need mock
when programming with erlang ?
.

The answer could be we don’t need any mock library because it’s
already part of the language
.

Let me explain a little more my vision of mock in Erlang.

The main purpose of the mock is to replace something
complicated by something very simple that you know the
behavior and that you can control. Using this mock, your tests will
only focus on one class module and forget all about the
environment of the complicated thing.
Using good unittest practices in OOP, you’ll pass all needed object in
the constructor of your classes, so you’ll be able to use mock in your
unittests.
In Erlang, we can’t use this technique because we don’t have
constructors however we can write good unittest.

  • Erlang is a concurrent programming language so we might have to
    test relationships between several processes. In order to test
    processes one by one, we can just spawn a small process in our tests
    and then pass its pid to the process under test. After that the
    only thing to do it to implement the message passing between
    processes. This technique is very close to the one used in OOP and
    their constructors.
  • Erlang is a functional programming language. One of the most
    interesting feature of FP is high order functions. It allows
    you to pass functions to your functions. Usually, high order functions
    are used to build generic algorithms but they can also be used to
    modify function behavior.
    Using fun to mock some behavior, oblige you to write some
    more tests:

    • Main function test with mock fun.
    • Production fun.
    • Real integration of the production fun in your application

Working on legacy code, it might be difficult to write tests. Of
course you can refactor to be able to use one of the previous case but
how to refactor without any tests ??. This observation make me realize
that sometimes we need something to intercept function calls.
The first technique I used was dbg. Adding traces on function
call, you can ensure that an expected side effect happened.
Anyway, if you need to setup a complete environment dbg
isn’t usable.
For those case a mock library could be useful. I have in mind
something that allow you to replace a module by another one.

There are the basic unit tests for this module

-module(mock_test).

-export([test /0]).

test () ->
    lazy_way () ,
    dynamic_way(),
    ok.

lazy_way () ->
    "i'm the production code" = my_module: who(),
    mock: replace_module (my_module, my_mock_module),
    "I'm the mocked code" = my_module: who (),
    mock: uninstall (my_module),
    "i'm the production code" = my_module: who(),
    ok.

dynamic_way () ->
    "i'm the production code" = my_module: who(),
    mock: start (),
    mock: add_module(my_module),
    mock: set_answer (my_module, who, "I'm the mocked code"),
    "I'm the mocked code" = my_module: who (),
    mock: set_answer (my_module, who, "Oops did it wrong"),
    "Oops did it wrong" = my_module: who (),

    [{my_module, who, []}, {my_module, who, []}] =  mock: calls (),
    mock: uninstall (my_module),
    "i'm the production code" = my_module: who(),
    ok.

Tags: ,
Posted in Uncategorized | Comments (0)

Posted on Sunday, 14th September 2008 by charpi

The summer wasn’t as productive as I would have liked. Anyway I took some time to think about my current professional life. Those thoughts gave me some conclusions:

  • I really need some method to organize myself. I bought Getting things done some time ago and my mission now is to read it and find a way to implement it.
  • My extra work need more visibility. It’s the reason why I started a Trac site and a GitHub repository. My expectations with this are double: job opportunities and increase the erlang footprint in France
  • My vision of agility need some clarifications

Tags: , ,
Posted in Uncategorized | Comments (0)

Posted on Sunday, 14th September 2008 by charpi

Since the beginning I use pyblosxom as my blogging system.One day I heard that my site was drab. As I’m not an expert in web design I searched a tools which can handle more things for me (especially nice themes). I decided to give a chance to WordPress due to its good reputation.
We’ll see if I made a good choice.

Tags: ,
Posted in Uncategorized | Comments (1)

Posted on Saturday, 6th September 2008 by charpi

In a previous post, I was arguing that selenium-rc missed an erlang library, so I did it.

The communication protocol is very simple, so it was very easy to implement it with erlang. At the time of the writing the only things I didn’t tested (and implemented) are unicode support and exponential number in response.
I know that the number of code line isn’t a ‘real’ good metric, but all the code for this binding is about 400 lines of code (code, unit test and acceptance test). I think that it’s quite small…

All selenium server commands are described in a xml files, so OpenQA used a XSL spreadsheet to generate all client bindings. For my erlang version, I didn’t’ use this strategy for 2 reasons. I only want to have erlang code. XSL is a bit complex so I tried erlang first but it’s not the main reason.

Functional programming offers us another way of thinking so I tried to explore it a little more. For example, classic client bindings have a function (or method) for each selenium command. I don’t think that it’s useful to have such a list, we can use simple erlang atoms to choose the command to send. With my strategy I only need one function
to be able to handle all selenium commands. By extension, why limit the command that an user could send ? The protocol can be used with any kind of test server.

Update: you can find all informations about this library on the erl_selenium trac page.

Tags: ,
Posted in Uncategorized | Comments (0)

Posted on Sunday, 22nd June 2008 by charpi

There is long time that I didn’t published anything new on my blog.
The summer season is suitable to be more productive so I got some news.
The main thing is the birth of a trac instance dedicated to my ‘open source’ works.
Most of them are just ideas or proof of concept but they are usable.
I invite you to browse my Wiki.

Tags: ,
Posted in Uncategorized | Comments (0)

Posted on Wednesday, 24th October 2007 by charpi

Valtech Days are over for the year. Our talk with Jacques Couvreur on Pair Programming was better (from my point of view) that during last XP-Days. As good agilists, we improve ourself at each iterations :-D.

Our slides are available here Pair Programming Valtech_days 2007 (46).

Tags: ,
Posted in Uncategorized | Comments (0)

Posted on Saturday, 29th September 2007 by charpi

For the 2007 edition of the Valtech Days I’ll do with Jacques Couvreur an refactored version of the speech we did for the french XP Days.

This presentation about Pair Programming will try to show the differences between “2 people in front of a PC” and the real pair programming.

Posted in Uncategorized | Comments (0)

-->
About me Downloads