search the lab

Embedded Testing with Unity & CMock (by Mark)

Embedded Testing with Unity & CMock

James Grenning's book (features Unity)

Test Driven Development for Embedded C

Topics

Entries in Compile (1)

Tuesday
Feb152011

Basic Testing with Unity

How Tests Are Handled

Let's talk about unit testing. The goal of unit testing is to get you to write robust modules which don't have a lot of dependencies.

The tests don't get baked into your final release artifact.

Instead, you link each module with its own test, Unity, and a test runner. These compile down to an individual executable, which you either run locally on your PC as a native application or you run in your favorite target-specific simulator. Repeat this with each of the modules in your application.

If your release build was made of only three modules, named creatively A, B, and C, you would create three test builds, like our handy dandy diagram shows.

Each test file is written to test that module. Depending on the complexity of the module under test, the test file may contain a single test, dozens, or even hundreds (though this probably suggests your module is too big or too complex).

Unity always works this way, combining the things you are immediately testing into an exe and running it before moving on to the next module. You can even compile multiple "real" modules together and test them as a larger unit (an "integration test") or combine with mocks. See the intro to mocking article for more details.

The Test File

So what does the inside of that test file look like? How do you actually write a test? Let's look at a really simple test file. This test file is going to test a function which is supposed to add two integers and return the result. The integers are treated like degrees. Let's say it lets you enter whatever numbers you want, but the output should always be between 0 and 359.

TestDegreeFunctions.c:

#include "Unity.h"
#include "DegreeFunctions.h"

void setUp(void)
{
}

void tearDown(void)
{
}

void test_DegreeSum_Should_HandleSomeEasyNumbersThatAreInRangeSum(void)
{
    TEST_ASSERT_EQUAL_INT(0, DegreeSum(0, 0));
    TEST_ASSERT_EQUAL_INT(130, DegreeSum(55, 77));
    TEST_ASSERT_EQUAL_INT(359, DegreeSum(350, 8));
}

void test_DegreeSum_Should_HandleSomeEasyNumbersInRangeButNotSum(void)
{
    TEST_ASSERT_EQUAL_INT(80, DegreeSum(350, 89));
    TEST_ASSERT_EQUAL_INT(0, DegreeSum(359, 1));
}

void test_DegreeSum_Should_HandleSomeWeirdNumbers(void)
{
    TEST_ASSERT_EQUAL_INT(0, DegreeSum(-33, 33));
    TEST_ASSERT_EQUAL_INT(180, DegreeSum(-180, 0));
    TEST_ASSERT_EQUAL_INT(3, DegreeSum(360, 2));
}

So there you go. Three tests, each with multiple asserts. Let's take that apart a bit.

First, note that we include the header of Unity (so that we get all those TEST_ASSERTs... there are many more of those, but we'll discuss those later. Also, we need to include the header of the module we are testing (in this case "DegreeFunctions.h").

Then, we have a setUp and tearDown function... These are convenience functions for you... setUp will be called before each test. The tearDown will be called after each test. So if you have any universal things to set up or clean up, that's the place to do it.

Finally, you've got the tests themselves. This is where you're going to spend more of your attention, obviously. Unity comes with some helpful scripts for automatically detecting your test functions. It does this for you if you name your functions something that starts with test. Unless you are using parameterized tests (more on these later), they'll take no arguments and return nothing.

We'll talk about the actual tests themselves in the next segment.