Testing Legacy Code

We’re working on adding significant new functionality to a legacy system. The budget doesn’t support a complete re-write. None of the legacy code has tests. The application domain is automotive testing. The particular problem at hand is controlling a throttle actuator (a simple robot that activates the throttle of a car while it’s being tested.)

The challenge

Legacy C source, 1600 lines. Many authors, 15+ years old. Complex if/else logic blocks with multiple clauses in conditionals. Several global variables. Throttle commands sent out serial port. Shared memory global variables via CPP macro interface.

How to add functionality in a TDD fashion for moving the robot smoothly?

The Solution

The approach we took preserved the interface for the legacy code, required simple enough changes that we were pretty confident we hadn’t broken anything (though we can only run the system to know this…), gave us a way forward to use TDD for new functionality, lets us run the new test suite without involving hardware, and only took 1.5 person hours to implement.

Where We Started

Legacy C source, 1600 lines. Many authors, 15+ years old. Function declarations at the top, implementations below. Complex if/else blocks with multiple clauses in conditional. Defines scattered in file. Several global variables. Throttle commands sent out serial port via SendCmd() function. Shared memory global variables via CPP macro interface. Main function of 100 lines with a while(1) loop.

Our Goal

Create new, testable implementations of functions which move the throttle. Customer wants smoother throttle movement using adaptive acceleration and velocity. Functions that do this must use and set global shared variables, and send bytes out the serial port. Tests should run without requiring other processes, or using hardware.

What We Did

1. Created SystemVariables class

Get and Set method for each system variable


#define ThrottleTeachMode shared_global_memory[offset];

replaced by

1
2
3
4
class SystemVariables {
int sv_ThrottleTeachMode();
void sv_ThrottleTeachMode(int mode);
};

if (ThrottleTeachMode) {

become

1
2
SystemVariables* sv = new SystemVariables();
if (sv->sv_ThrottleTeachMode()) {

2. Created Throttle.h

1
2
3
4
5
6
class SerialPort
SerialPort(SystemVariables* sv);
virtual void SendCmd();

class Throttle
Throttle(SystemVariables* sv, SerialPort* port);

3. Modified Throttle.c

1
2
3
4
5
6
7
8
9
global serial port object ref
SerialPort* serialPort;

change SendCmd() instances to serialPort->SendCmd() with editor global replace

main()
creates system variables object
creates a SerialPort object, initializes global reference
creates Throttle(sv, port)

moved legacy functions-under-test to instance methods of Throttle class

moved a few utility functions used only by f-u-t to private methods of Throttle class

moved #defines from Throttle.c to Throttle.h
both legacy and Throttle class can access

allocate a Throttle object for main’s use


Throttle theThrottle(sv, port);

replace invocation of “top” function in main loop with call to

1
2
theThrottle.process()
process();

becomes


theThrottle.process();

4. Created Throttle.cpp

Instance methods to replace f-u-t
void process()
calls to other f-u-t “just work” (members of the class)

5. Created ThrottleTest.cpp

MockSystemVariables : public SystemVariables
override SVs used by f-u-t

MockSerialPort : public SerialPort
override SendCmd()

create Throttle object to test against, supplying mock objects
Throttle testThrottle(new MockSystemVariables, new MockSerialPort);
testThrottle.f-u-t();
assert(something about testThrottle);
assert(state of mock serial port);

test methods for new methods of Throttle following TDD practices

This entry was posted in Testing and tagged . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">