HOWTO: Testing

This page will cover different types of testing, and how we plan to go about it.

Unit Testing Framework

Our testing framework is comprised of two main components: Unity testing and TEST_IN_TASK testing. These tests only work on x86, not on our arm platforms.

Unity

Unity is a Unit Testing framework we use to generate and run our tests. It basically allows you to declare functions which are run independently, and add assertions in these functions to show that code is behaving as we expect. It doesn’t have any RTOS functionality, but is really good at verifying any logic that doesn’t use freeRTOS functionality.

Here’s an example of a unit test from the fwxiv tests for our GPIO library. You declare a void function, prefixed with test_ and write the functionality you want inside. In this case, it sets up the pin, asserts that it was set up correctly, then ensures checking the state returns the value it was initially set to (notice that in the init settings the state is HIGH).

Each test function is run individually, and the same setup_test and teardown_test functions defined in the file will be called before/after respectively.

Every test file has three parts:

  • A setup_test function, which is run before every test. It initializes all the libraries the tests need.

  • A teardown_test function, which is run after every test. Usually it’s empty, but it still has to be there.

  • Test functions, which is any function that starts with test_. They can use assertions like TEST_ASSERT_EQUAL to test conditions.

Task Testing

For testing code that uses FreeRTOS functionality, we have added functionality on top of the unity framework. This is defined in "task_test_helpers.h".

The macro TEST_IN_TASK is used to indicate to the test runner that the following function should be run inside the “test task”. The test task is simply a task created at the highest priority, which runs the test function inside of it. This test function can call tasks_init_task() to create other tasks, which will start them immediately since the scheduler is already started.

The TEST_IN_TASK Macro also controls starting the scheduler, and stopping it after the function has been executed.

A simple example from test_tasks.c:

static bool s_task_started; // Called before execution of test_running_task void setup_test(void) { s_task_started = false; log_init(); } void teardown_test(void) {} // A simple task to test. TASK(my_task, TASK_STACK_512) { LOG_DEBUG("my_task started\n"); s_task_started = true; // Loop forever, because tasks should not exit. while (true) { } } TEST_IN_TASK void test_running_task() { LOG_DEBUG("started first test\n"); // Start the task: note no need to call tasks_start() because we're inside a test task and // FreeRTOS is already running. tasks_init_task(my_task, TASK_PRIORITY(1), NULL); // The task doesn't start immediately because the test task has the highest priority. TEST_ASSERT_FALSE(s_task_started); // To let it run, use a delay (or preferably semaphore). delay_ms(20); // The task should have run. TEST_ASSERT_TRUE(s_task_started); }

Running Tests

To run a test, be sure you are ssh’d into vagrant and then you can use the command

scons test --<library/project>=... --test=... --platform=<x86/arm>

Project Tests

What are Project Tests?

Projects tests are C files, stored in the projects/project_name/test/ directory, and contain code used to verify our projects functionality. They will run exclusively on x86, and verify any logic that does not require interacting with hardware.

FSM tests

See projects/fsm_demo/tests/test_fsm1.c for a detailed example of how to FSM test