Mock Objects in C

Hello World,

This is a discussion about using mock objects when testing software written in C.  With more dynamic languages, such as Python and Ruby, mock objects (or mocks for short) are much easier to implement.  With a compiled language such as C, we must find a way to easily create mocks.  The criteria for “easy” is that it works well with production code and doesn’t require a lot of overhead when using.  Mocks are not very useful you have to write C code in an atypical way (e.g. a custom framework).  The emphasis will be on C for embedded systems, since this is an ecosystem where C is still is very prevalent.

What are Mocks?

A ‘mock object’ is an object that simulates the behavior of a more complex objects.

The Mock Module Pattern

In the C language, it is common to write modules, where a module is a related set of functions in a single .c file, and an associated .h file with the function declarations and exported variables.  This style of programming with .c is good practice because the modules are modular (funny how that works out 😉 ).  Modular code is easier to test.  Modular code is also easier to replace.  That is the key to the Mock Module pattern.  Given module files foo.h and foo.c, to implement a mock version, then provide a different implementation, such as mock_foo.c.  The header file, foo.h stays the same and is used in both the production code and the test code.

The mock is introduced at the link stage of the build.  Instead of linking the production functionality, a simpler version designed for unit testing is linked.

The benefit of the Mock Module pattern is that is does not require any changes to production code.  It also encourages modular C code.

The drawback to the Mock Modular pattern is that it does require the code to be modular.  If there is “too much” functionality in a given module, then it may be hard to create a suitable mock object.  Similarly, if functionality is spread over multiple files, then multiple mocks must be created, which adds complexity.

The Mock Class Pattern

C allows the definition of structs.  The Mock Class pattern relies on a struct holding variables and pointers to its functions.  For example:

/* Defining Foo */

/* Forward reference */
struct Foo;

/* Define class function pointer types */
typedef int (*FooIncrFunction)(Foo* self);

/* Define "class" */
struct Foo
{
  int i;
  FooIncrFunction Incr;
};

/* Define function implementation */
int FooIncr(Foo* self)
{
  if (!self) return 0;
  ++self->i;
  return self->i;
}


/* Using Foo */

/* Create a new foo */
Foo foo = { .Incr = FooIncr };

/* Call Foo method */
int i = foo.Incr(&foo);

This allows us to simply provide alternate implementations for the member functions.  For example, suppose in the Foo example above that FooIncr was very expensive to calculate.  Instead, for testing purposes, it is sufficient that the function return a reasonable value for a test.

int MockFooIncr(Foo* self)
{
  if (!self) return 0;
  return 42;          
}


/* Using Foo */
Foo = foo { .Incr = MockFooIncr };

/* Call mock Foo method */
int i = foo.Incr(&foo);

The drawback to the Mock Class Pattern is that requires a fairly rigid programming style.  This may not be useful to existing code bases that do not use this style.

An advantage of the Mock Class Pattern is that it is independent of the Mock Module Pattern, so they can be used separately or together.

 In Conclusion

I hope you have found this post helpful, and possibly learned an easy way to create C mock objects for use with unit testing.

 

Review of Unity – Compact Test Framework for C

Hello world,

This is a review of Unity, a compact test framework for C.

Some of you may say, “C… ugh, why not use < insert your favorite language (YFL) here >”.  Well, YFL may have lots of bells and whistles, beautiful syntax, maximum expressiveness, supports < insert YFL feature here >, and so on.  However, for some environments, C is the “best” choice.  The environment is defined as a loose coupling between desired target platform and external political constraints (e.g. your manager/department/company doesn’t like YFL).  Embedded computing environments are especially attracted towards the C language.  So, let’s just accept as a given that we are using the C language for project NGT (Next Greatest Thing).

As an embedded developer using C, you may be faced with the following challenges:

  1. Artificial deadlines dictated by management.
  2. Hardware still in the prototype stage.
  3. Amorphous acceptance requirements.
  4. Limited access to resources.

How do you survive in this harsh environment?  You equip yourself with the tools for survival.  One of the tools you should have in your toolbox is a good unit testing framework.  A good unit testing framework I recently encountered is Unity – Compact Test Framework for C.

How did you know?

I first learned about Unity from the excellent book, “Test Driven Development for Embedded C” by James W. Grenning.  You can read more about James on his blog.  The remainder of this post is mainly a remix of the highlights presented in this book, along with my own opinions and whimsical anecdotes.

If you aren’t practicing Test Driven Development (TDD), you should be.  If you skimmed over that last sentence, here it is again:

You should be practicing Test Driven Development

The hardest part about practicing anything (including TDD) is getting started.  Where do you begin? What do you use? How can you justify learning something new when you don’t have time to do the things you already know?  To help you out, I’ll give you some answers: You begin now, using Unity, because your projects will be completed faster and delivered with less bugs.

There is both U and I in Unity

If you aren’t familiar with Unity, you are probably asking yourself, “so what’s so great about it anyway?”  Here is a short list of nice features:

  • It’s small.  To use it in your first project, there is one .c file to compile.  If you use the fixture (which I would recommend), there are two .c files.
  • It’s easy.  Unity follows the xUnit patterns, so the concepts are fairly portable across many testing frameworks.  You have assertions that are contained in tests, organized in groups, that are ran.
  • It’s portable.  Most standard C compilers should have no problems compiling projects using Unity.
  • It’s free.  The cost of using Unity is close to zero (you only need internet access to get it).  It uses the MIT license, so it is free as in beer and speech.  You don’t deliver code with Unity compiled in it, so Unity is perfectly happy to sit beside your production code to support tests.  Also, because it is small, you can use it with some of the popular code size limited compilers such as IAR Embedded Workbench Kickstart edition and TI Code Composer Studio.  It will also work with GCC and Microsoft Visual C++ Express edition.

Because Unity is small, easy and portable, it has a shallow learning curve (if you already know C).  Once you start a project with Unity, you can continually add tests throughout the life cycle of the project.  Therefore, it is appealing  to the novice, the experienced, and the frugal user alike.

So what do you do?

First, get Unity.  There is a link to download it here:

http://sourceforge.net/apps/trac/unity/

For a project that uses Unity, I typically make a folder near the top of the directory structure called ‘test’ and and copy the unity folder into it.

+ NGT
-+ src
-+ test
–+ unity

Unity is based on assertions.  There is a large list of assertion macros that are defined by Unity.  Some examples are:

TEST_ASSERT_NULL(value);
TEST_ASSERT_TRUE(value);
TEST_ASSERT_FALSE(value);
TEST_ASSERT_NOT_EQUAL(expected, result);
TEST_ASSERT_EQUAL_STRING("hello", hi);
TEST_ASSERT_EQUAL_INT32(expected, result);

Assertions are made within tests.  To define a test easily, use unity_fixture.h.  This makes defining tests as simple as:

TEST(my_test_group, test_bar)
{
  /* setup */
  foo();

  /* exercise */
  int result = bar();

  /* verify */
  TEST_ASSERT_EQUAL_INT32(0, result);

  /* teardown */
  shoo();
}

Tests are ran as groups.  The group name is defined as the first argument in the TEST macro.  To define a test group, you would do the following:

TEST_GROUP_RUNNER(my_test_group)
{
  RUN_TEST_CASE(my_test_group, test_bar);
}

A test group has setup and tear down methods that are called before and after each test.  These are defined as follows:

TEST_SETUP(my_test_group)
{
  /* do test setup */
}

TEST_TEAR_DOWN(my_test_group)
{
  /* do test tear down */
}

Finally, to run the test group, you can do the following:

int main()
{
  RUN_TEST_GROUP(my_test_group);
}

And the winner is…

The benefits of TDD with Unity may not be apparent at the beginning of a project.  However, if you are diligent with your tests (i.e. writing tests before writing code), then you will be continually adding value to your project.  As the project matures and schedules tighten, you can add functionality to your product while continuously monitoring the software behavior.

So after managing to get that last minute feature in, while maintaining a reasonable level of confidence in your change, you may leave the office sying “Unity, God its great!  Beer is good and people are crazy…”

~ fin ~