Mar 18, 2011

Embedded Unit Testing: In the Trenches Part 1


A Brief History

I recently wrote a unit testing framework for the NetBurner family of products based on the UnitTest++ framework.  It's available on the NetBurner forums, and you you can watch an overview video on the framework, and  one on how to write some simple tests against it.  There's a lot of resistance to using Unit Testing in the embedded world. I hope to address some of the unique challenges of doing embedded UnitTesting.  Since the NetBurner's claim to fame is its out-of-the-box support for TCP, there's a lot of code I reuse for every project and none of it is hardware specific. Every project I write has multiple processes, a tcp server, a web server, serial port debug output and a command processor to name just a few. It was helpful and not too difficult to write unit tests for all of my standard library that takes advantage of these facilities. It's can be less obvious how to write the unit tests when you start talking to proprietary hardware. The rest of this post is going to talk about one approach to doing that. Since most embedded programmers are familiar with programming devices over serial ports, that's where I'm gong to start.

Serial Port programming

One very common programming task in the embedded world involves programming a device over a serial port. In this post I'm going to talk about a standard RS232 serial port but the technique can just as easily be applied to other RS flavors as well as SPI, I2C etc.
I was tasked with programming the Matrix Orbital GTT touchsreen, this device uses a binary stream of bytes sent to it over RS232 to invoke the API commands. Now of course I could still write unit tests by attaching the device, running the tests and seeing if things show up correctly. However, while I think that's very worth doing, it's more of an integration test than a unit test and since it requires a man-in-the-loop it's not an automatic test.  It requires a working serial port and the actual device to program. I wanted a unit test that could validate a lot of my library without either one.
Without thinking about unit testing I might be tempted to create a TouchScreen class that just internally writes directly to the serial port. Of course I don't like writing to C APIs to begin with so I typically wrap up needed serial port functionality into a SerialPort class. It makes configuring all those pesky settings much cleaner. So then I  might be tempted to just new up an instance of the SerialPort class and use that.  That would still  lock me into the single SerialPort class. I NEVER want to modify target code for the sole purpose of supporting unit tests. If I did I might be tempted to just modify SerialPort so that I could set flags and have it behave differently if unit tests were being run. There's a better way.

Interfaces and DI to the Rescue

A better approach is to rely on Dependency Injection. My TouchScreen class will just take a SerialPort class as a parameter. Actually it  will just take a SerialPort interface, in  C++ that means a pure abstract class that defines the public methods I want both my UnitTesting capable serial port and my real serial port to support. The advantage is in my shipping code I'll be using the functionally unadulterated SerialPort class that I always use.  In my unit tests I'll be using some other class that supports the interface but doesn't need either a serial port or a device to work. It's possible I could even use a mock object for that class. At first I'm only interested in writing to the device (as opposed to reading from the device) so here's the minimal IStreamWriter interface I needed:
SNAGHTML75b3ee9

Some Other Class

So what's the other class going to look like? We know what methods (at a minimum) that it will have but if it's not writing data out a serial port what will it do? For the sake of unit testing we want to know if the data that went out the serial port is the data we expected. That means we probably need to store that data somehow and then provide a way to get that data back to the unit test. I decided I would just write into two queues. One for the vector<byte> data and one for the String data. I could have converted the strings into vector<byte> and just used one queue but I since the actual serial port uses two methods for writing these structures I thought it would be advantageous to have two methods for storing them.  Since this class just holds onto data I decided to name it StreamBucket. Here's the declaration:
SNAGHTML75c2716

 

In part 2 of this series I'll talk about the specifics of using StreamBucket to test the TouchScreen class as well as the unit tests needed for StreamBucket. I'll also talk about a refactoring that fell out that made testing easier and the code base better.

About Me

My photo
Tod Gentille (@todgentille) is now a Curriculum Director for Pluralsight. He's been programming professionally since well before you were born and was a software consultant for most of his career. He's also a father, husband, drummer, and windsurfer. He wants to be a guitar player but he just hasn't got the chops for it.