Nifty bio photo

Nifty

Nifty Testing Framework

Github

Tutorial 5: Testing With Proper

Files For This Tutorial

Tutorial

This tutorial will guide you through using Nifty Contiki together with PropEr, a property based testing framework. This tutorial covers the specifics using Nifty Contiki. It is strongly recomended to read the Proper Documentation.

Firmware

We use the same Firmware as in the former Tutorial.

Testcase

We need to start up the simulator with the right simulation file, subscribe to the motes and wait until the nodes have been initialized:

setup() ->
    {ok, Handler} = nifty_cooja:start("$CONTIKI/tools/cooja", "answer_sim.csc", []),
    Motes = nifty_cooja:motes(Hanlder),
    [ok = nifty_cooja:mote_listen(Handler, MoteID) || MoteID <- Motes],
    [true = nifty_cooja:wait_for_msg(Handler, MoteID, 1000, "Starting 'Process answer'\n") || MoteID <- Motes].

Now we can write our property:

answer_property() ->
    ?FORALL(I, integer(), mote_answer:answer(Handler, Mote, I) =:= I+10).

In order for the code to work, we need to get the Handler of the simulation:

answer_property() ->
    ?FORALL(I, integer(),
        begin
            {running, Handler} = nifty_cooja:state(),
            mote_answer:answer(Handler, Mote, I) =:= I+10
        end).

Now we just need to take care about the Mote argument. We want the motes to be generated, like I. One way of doing this is by parameterizing our property with a list of motes:

answer_property(Motes) ->
    ?FORALL({I, Mote}, {integer(), oneof(Motes)},
            begin
                {running, Handler} = nifty_cooja:state(),
                mote_answer:answer(Handler, Mote, I) =:= I+42
            end).

Now we can run our tests:

1> c(tut).
{ok, tut}
2> tut:setup().
[true, true]
3> {running, Handler} = nifty_cooja:state().
{running, <0.33.0>}
4> Motes = nifty_cooja:motes(Handler).
[1,2]
5> proper:quickcheck(tut:answer_property(Motes)).
...................................................................
ok
6> nifty_cooja:exit().
ok

Now we want to automate this setup and finalizing phase. We can do this by packing the code into an EUnit testcase:

answer_test_() ->
    {timeout, 3600, ?_assertEqual(true, test_func())}.

test_func() ->
    setup(),
    {running, Handler} = nifty_cooja:state(),
    Motes = nifty_cooja:motes(Handler),
    R = proper:quickcheck(answer_property(Motes), [{to_file, user}]),
    nifty_cooja:exit(),
    R.

Self-Contained Tests

Our testcase is not self-contained yet. For each generated input we progress the simulation a bit further. This means, that the flowing tests depend on the state the simulation was left in from former tests. This is bad, because we can not be sure to reproduce an error if we find one.

We can fix this by pulling the simulation setup into the property. We still need to give the mote IDs to the property:

setup() ->
    Handler = nifty_cooja:start("$CONTIKI/tools/cooja", "$PWD/simulation.csc", [gui]),
    Motes = nifty_cooja:motes(Handler),
    [ok = nifty_cooja:mote_listen(Handler, MoteID) || MoteID <- Motes],
    [true = nifty_cooja:wait_for_msg(Handler, MoteID, 1000, "Starting 'Process mote_answer'\n") || MoteID <- Motes],
    Handler.

answer_property(Motes) ->
    ?FORALL({I, Mote}, {integer(), oneof(Motes)},
            begin
                Handler = setup(),
                R = mote_answer:answer(Handler, Mote, I) =:= I+42,
                nifty_cooja:exit(),
                timer:sleep(100),
                R
            end).

test_func() ->
    Handler = setup(),
    Motes = nifty_cooja:motes(Handler),
    nifty_cooja:exit(),
    proper:quickcheck(answer_property(Motes), [{to_file, user}]).

answer_test_() ->
    {timeout, 3600, ?_assertEqual(true, test_func())}.

We can now run the test:

6> c(tut).
{ok, tut}
7> nifty:compile("answer.h", mote_answer, []).
generating...
ok
8> c(mote_answer).
{ok, mote_answer)
9> eunit:test(tut).
..................................................
..................................................
OK: Passed 100 test(s).
  Test passed.
ok
Previous Tutorial Tutorial Files Next Tutorial