Skip to content

Writing unit tests

Daniele Lacamera edited this page Apr 16, 2015 · 5 revisions

How to build

See Setting up the environment and Testing/Unit Tests

Concept

Every picoTCP component is shipped with its own set of unit tests. Unit tests are based on libcheck. The first version of the unit test platform is maintained in a single file: test/units.c. This module provides a set of unit tests for the core of the stack and the generic tools.

Unit test creation

Unit tests for modules are implemented in their own test/unit/modunit_$(MODULENAME).c file. This file can be created automatically using the script mkunits.sh.

Suppose that we just created a simple picotcp module, which exports a function that broadcasts one udp datagram to port 555.

/* pico_poke.c */
#include <pico_stack.h>
#include <pico_socket.h>

static int socket_cb(uint16_t ev, struct pico_socket *s)
{
}

static int do_pico_poke(char *msg, int len)
{
    struct pico_socket *s;
    int ret;
    pico_err_t err;
    struct pico_ip4 bcast = {
        .addr = 0xFFFFFFFF;
    };

    if ((len < 1) || (msg == NULL)) {
        pico_err = PICO_ERR_EINVAL;
        return -1;
    }

    s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, socket_cb);
    if (!s)
        return -1;
    ret = pico_socket_sendto(s, msg, len, &bcast, short_be(555));
    if (ret < 0)
        err = pico_err;
    pico_socket_close(s);
    pico_err = err;
    return ret;
}

int pico_poke(char *msg, int len)
{
    return do_pico_poke(msg, len);
}

We can generate unit tests using the script as follows:

test/mkunits.sh modules/pico_poke.c

Warning: the script creates incomplete code, and sometimes may fail recognizing your functions signatures. mkunits.sh is only intended to automate the very boring parts of creating a new unit test module, such as the needed include files, the suite creation, etc.

The file modunit_pico_skull.c file has been created, and contains a skeleton for our unit tests:

#include <pico_stack.h>
#include <pico_socket.h>
#include "modules/pico_poke.c"
#include "check.h"


START_TEST(tc_socket_cb)
{
   /* TODO: test this: static int socket_cb(uint16_t ev, struct pico_socket *s) */
}
END_TEST

START_TEST(tc_do_pico_poke)
{
   /* TODO: test this: static int do_pico_poke(char *msg, int len) */
}
END_TEST


Suite *pico_suite(void)
{
    Suite *s = suite_create("PicoTCP");

    TCase *TCase_socket_cb = tcase_create("Unit test for socket_cb");
    TCase *TCase_do_pico_poke = tcase_create("Unit test for do_pico_poke");


    tcase_add_test(TCase_socket_cb, tc_socket_cb);
    suite_add_tcase(s, TCase_socket_cb);
    tcase_add_test(TCase_do_pico_poke, tc_do_pico_poke);
    suite_add_tcase(s, TCase_do_pico_poke);
return s;
}

int main(void)
{
    int fails;
    Suite *s = pico_suite();
    SRunner *sr = srunner_create(s);
    srunner_run_all(sr, CK_NORMAL);
    fails = srunner_ntests_failed(sr);
    srunner_free(sr);
    return fails;
}

Mocking

Some functions in picoTCP can be mocked, meaning that they are defined as weak symbols in the testing environment. These functions are those defined with the modifier MOCKABLE in front. This is the case of the pico_socket_sendto() function, which is often useful to check the payload that is being transmitted by the module under test to the socket interface.

Clone this wiki locally