Skip to content

Unit Testing

Isaac Pedisich edited this page Nov 29, 2017 · 1 revision

DeDos provides a test framework to test functionality and memory-leaks in the provided source code. This testing framework can be used to test runtime, global controller, and MSU code.

Unit testing relies on the Check framework, and utilizes a subset of its test-case and assert functionality.

Tests are run with make test, make runtime-test or make global_controller-test

Setting up tests

Placement

The source code in DeDos is organized into several directories:

Dedos/src/
├── common
├── global_controller
├── legacy
├── msus
└── runtime

Unit tests corresponding to a particular file must appear in the same directory, but under the test folder:

Dedos/test
├── common
├── dedos_testing.h
├── global_controller
├── msus
└── runtime

The tests for a particular file should be named the same as the file under test, with the name preceded with the string Test_. For example, the tests for the file: src/common/communication.c should be placed in the file: test/common/Test_communication.c

This must be done to allow static functions and variables in the file under test to be accessed by the test functions.

Setting up the test file

The first thing that should be done in the test file is always including the header that defines the test macros, dedos_testing.h

Following that, the source code under test should be included. This means the .c file, not the .h file.

Including the .c file in this way allows the test code to have access to static files and functions, allowing testing to be more thorough, and easier to set up and tear down.

In the case that your tests need access to static variables in other files, those can be included as well, provided that the relevant variables are defined in the test's Test_*.mk file. This variable must be equal to the basename of the file under test, followed by _DEPS.

As an example .mk file:

# test/runtime/Test_controller_communication.mk
controller_communication_DEPS:=runtime/runtime_dfg.c runtime/runtime_communication.c

And the corresponding test file:

// test/runtime/Test_controller_communication.c
#include "dedos_testing.h"

// Include the file under test:
#include "controller_communication.c"
// And any additional files listed in the .mk file
#include "runtime_dfg.c"
#include "runtime_communication.c"

Writing tests

See check's documentation for information on the capabilities of the testing framework.

Defining test functions

Writing tests and selecting the tests to run are done via a wrapper-macro around Check's START_TEST and END_TEST function. The DeDos functionality is identical with a slight name-change:

START_DEDOS_TEST (test_name)
{
  /* unit test code */
}
END_DEDOS_TEST

The test_name should be a descriptive name for the functionality that the test is testing. In particular, it should include the name of the function under test, with (optionally) the condition it is checking.

For example, tests for a function fn_name might be test_fn_name__success and test_fn_name__fail_invalid_inputs.

Macros have also been provided to easily add each of the tests to the test case and suite. At the bottom of the file, include the lines:

DEDOS_START_TEST_LIST("file_name")

DEDOS_ADD_TEST_FN(test_name)
DEDOS_ADD_TEST_FN(test_name2)
DEDOS_ADD_TEST_FN(test_name3)

DEDOS_END_TEST_LIST()

This will ensure that each test is run when the file is executed. ** Note:** The main(int argc, char *argv[]) function is wrapped in the START_TEST_LIST macro and does not have to be explicitly written.

Testing code

Tests should be provided using (Check's API)[https://libcheck.github.io/check/doc/doxygen/html/check_8h.html].

In particular, the following macros are especially useful (though any in the framework can be used).

// Fail if condition is false
ck_assert(<must_be_true>);
// Fail if condition is false and print message
ck_assert_msg(<must_by_true>, "Failure is %s", "unacceptable");

int i1, i2;
// Fail if integers are not equal
ck_assert_int_eq(i1, i2);

Clone this wiki locally