Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to begin writing unit tests for a legacy Embedded C application - very tightly coupled modules?

I am currently working on a code base, that has never had any unit tests written on it. It has been written for a 16-bit Embedded processor, and I would like to start to add unit tests for all the code that I write, at a minimum and then extend this to other parts of the code.

My problem with this is, I have found that each module (.c file) at the application level, seems to be tightly coupled to other C files in the project. For any given file, this may be anywhere from 2-10 files down.

  1. How do I start to write the unit tests?
  2. What are the best/quick/most efficient ways to remove this tight coupling?
  3. Also the unit tests will be run on the PC, (32 bit) and the embedded code is for a 16-bit processor. How do I ensure this is taken care of when porting the code to the PC?
like image 465
IntelliChick Avatar asked Jun 28 '10 07:06

IntelliChick


2 Answers

Regarding #3 - making sure it is portable to PC, here's the strategy I use:

First, go through the embedded code and change any 'int' or 'unsigned long' to 'int16' or 'uint32' (or whatever convention you choose).

Wrap the section in the embedded header where you define the types inside a condition:

#ifndef CORE_TYPE_DEFINITIONS
#define CORE_TYPE_DEFINITIONS
typedef long int16;
/*...*/
#endif

create a "PC_Types.h" file which defines the same types for the PC.

#ifdef CORE_TYPE_DEFINITIONS
#error "Core Types already defined"
#else
#define CORE_TYPE_DEFINITIONS
typedef short int16;
/*...*/
#endif

In the PC project, create a wrapper for each embedded c file, which contains the following:

#include "PC_Types.h"
#include "ModuleX.c"  //the file under test

#include "TestHarness.h"   //verification functions

int TestModuleXUnit1(void)
{
   /* setup */
   /* call Unit1(); */
   /* verify post-conditions */
   return result;
}

By wrapping every file, you have all the coupled functions available as needed. #including the original source file in your wrapper file allows you to drop in updates to the embedded code directly from your source control system without any modification. Adding the test functions after the included source gives the test code full access to all the module's functions, even if they don't have a public header.

like image 82
AShelly Avatar answered Sep 28 '22 21:09

AShelly


I would begin by rereading Michael Feathers' Working Effectively with Legacy Code.

like image 23
just somebody Avatar answered Sep 28 '22 23:09

just somebody