Parameterized Unit Tests

Have you ever written a test which mostly consists of the same block of code over and over again with different parameters?

// paraphrased from projects/charger/test/test_control_pilot.c void test_various_duty_cycles(void) { uint16_t answer = 0; uint16_t actual = 0; // case 1 s_duty_cycle = 10; answer = 0; actual = control_pilot_get_current(); TEST_ASSERT_EQUAL(answer, actual); // case 2 s_duty_cycle = 97; answer = 60; actual = control_pilot_get_current(); TEST_ASSERT_EQUAL(answer, actual); // case 3 s_duty_cycle = 600; answer = 360; actual = control_pilot_get_current(); TEST_ASSERT_EQUAL(answer, actual); // more cases... }

Parameterized tests give us a way to perform this kind of repetitive yet thorough test concisely.

We can rewrite the above test like this:

TEST_CASE(10, 0) TEST_CASE(97, 60) TEST_CASE(600, 360) // ... more TEST_CASE calls void test_various_duty_cycles(uint32_t duty_cycle, uint16_t current) { s_duty_cycle = duty_cycle; TEST_ASSERT_EQUAL(current, control_pilot_get_current()); }

Parameterized tests are a great way to test your functions for a lot of edge cases at once. Each test case will run as a separate test; setup_test will run before each test case and teardown_test will run after each test case, and each case will print out on a separate line. You’ll get output that looks like this:

projects/charger/test/test_control_pilot.c:22:test_various_duty_cycles(10, 0):PASS projects/charger/test/test_control_pilot.c:22:test_various_duty_cycles(97, 60):PASS projects/charger/test/test_control_pilot.c:22:test_various_duty_cycles(600, 360):PASS ...

Warning: only integer literals, symbols defined outside the test file, strings, and derived expressions are currently supported in TEST_CASE calls. So:

This is because the Unity test framework (http://www.throwtheswitch.org/unity) literally copies the arguments you put in the TEST_CASE call to the generated test runner file, which runs your tests. It doesn’t have access to any of the symbols defined in your test file, but it does include everything your test file does. It’s also really dumb, so it does silly things like interpreting } as marking a new line.

Aside: the TEST_CASE macro is defined in test_helpers.h, so you’ll have to include it.