![Page 1: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/1.jpg)
®
IBM Software Group
© 2009 IBM CorporationInnovation for a smarter planet
Stopping the rotPutting legacy C++ under test
Seb RoseACCU 2011
![Page 2: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/2.jpg)
IBM Software Group | Rational software
2Innovation for a smarter planet
Agenda
Background
Unit Testing
Frameworks
Test & Mock: First Examples
Refactoring: Wrap Dependency
Refactoring: Extract Component
Refactoring: Non-Intrusive C Seam
Conclusions
Questions
![Page 3: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/3.jpg)
IBM Software Group | Rational software
3Innovation for a smarter planet
Agenda
Background
Unit Testing
Frameworks
Test & Mock: First Examples
Refactoring: Wrap Dependency
Refactoring: Extract Component
Refactoring: Non-Intrusive C Seam
Conclusions
Questions
![Page 4: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/4.jpg)
IBM Software Group | Rational software
4Innovation for a smarter planet
A brief history of DOORS
Developed in C in early 1990s
Home grown cross platform GUI
Heavy use of pre-processor macros
Server and client share codebase
Ported to C++ in 1999
No unit tests – ever
DXL extension language tests brittle
Success led to rapid team growth
Proliferation of products and integrations
![Page 5: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/5.jpg)
IBM Software Group | Rational software
5Innovation for a smarter planet
Challenges
Highly coupled code
Long build times
Developer ‘silos’
SRD - “Big Design Up Front”
Long manual regression test ‘tail’
Hard to make modifications without errors
No experience writing unit tests
![Page 6: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/6.jpg)
IBM Software Group | Rational software
6Innovation for a smarter planet
New direction Move to iterative development
Implementation driven by User Stories not SRD
All new/modified code to have unit tests
All unit tests to be run every buildNightly builds
CI server
Develop “Whole Team” approachAutomated acceptance tests written by test & dev
Test to pick up nightly builds
Align with Rational toolset
![Page 7: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/7.jpg)
IBM Software Group | Rational software
7Innovation for a smarter planet
Agenda
Background
Unit Testing
Frameworks
Test & Mock: First Examples
Refactoring: Wrap Dependency
Refactoring: Extract Component
Refactoring: Non-Intrusive C Seam
Conclusions
Questions
![Page 8: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/8.jpg)
IBM Software Group | Rational software
8Innovation for a smarter planet
Why Unit Test?
Greater confidence than Buddy check only
Fewer regressions
Tests as documentationdon’t get out of step with the code
“Legacy Code is code without Unit Tests” – Michael Feathers
Can drive out clean designs
![Page 9: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/9.jpg)
IBM Software Group | Rational software
9Innovation for a smarter planet
When to write Unit Tests?
ALWAYS
Test Before (TDD) tends to lead to cleaner interfaces
Test After tends to miss some test cases & takes longer
For TDD to work the component under test & the tests must build fast (< 1 minute)
You CAN make this possibleComponentisePartition
![Page 10: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/10.jpg)
IBM Software Group | Rational software
10Innovation for a smarter planet
Unit Test guidelines
Only test a single behaviour
Use descriptive names (as long as necessary)
Group related tests
Do not make tests brittle
Treat tests just like production code
Refactor to remove redundancy & improve architecture
Adhere to all coding standards
Tests are documentation
They must ‘read well’
![Page 11: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/11.jpg)
IBM Software Group | Rational software
11Innovation for a smarter planet
How to write the first Unit Test
Major refactoring needed to put “seams” in place
Patterns used extensively for initial refactoring:“Working Effectively With Legacy Code”
Link errors in unit test build point to unwanted dependencies
Replace dependencies with ‘injected’ mock/fake objects …… until you really are UNIT testing.
![Page 12: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/12.jpg)
IBM Software Group | Rational software
12Innovation for a smarter planet
A test is not a unit test if:
It talks to the database
It communicates across the network
It touches the file system
It can’t run at the same time as other unit tests
You have to do special things to your environment (such as editing config files) to run it
(Michael Feathers’ blog, 2005)
![Page 13: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/13.jpg)
IBM Software Group | Rational software
13Innovation for a smarter planet
Agenda
Background
Unit Testing
Frameworks
Test & Mock: First Examples
Refactoring: Wrap Dependency
Refactoring: Extract Component
Refactoring: Non-Intrusive C Seam
Conclusions
Questions
![Page 14: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/14.jpg)
IBM Software Group | Rational software
14Innovation for a smarter planet
Which framework to use?
We chose Googletest & Googlemock
Available from Googlecode
Very liberal open source license
Cross platform
Can use independently, but work together “out of the box”
Implemented using macros & templates
Easy to learn
Well documented
![Page 15: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/15.jpg)
IBM Software Group | Rational software
15Innovation for a smarter planet
Googletest
No need to register tests
Builds as command line executable
Familiar to users of xUnit:
Suites
Fixtures
SetUp, TearDown
Filters to enable running subsets
Handles exceptions
![Page 16: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/16.jpg)
IBM Software Group | Rational software
16Innovation for a smarter planet
Googlemock
Feature-rich
Dependency on C++ TC1, but can use Boost
Extensible matching operators
Declarative style (using operator chaining)
Sequencing can be enforced
Use of templates slows build time
Can only mock virtual methods
Still need to declare mock interface
Inconvenient to mock operators, destructors & vararg
![Page 17: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/17.jpg)
IBM Software Group | Rational software
17Innovation for a smarter planet
Agenda
Background
Unit Testing
Frameworks
Test & Mock: First Examples
Refactoring: Wrap Dependency
Refactoring: Extract Component
Refactoring: Non-Intrusive C Seam
Conclusions
Questions
![Page 18: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/18.jpg)
IBM Software Group | Rational software
18Innovation for a smarter planet
The first test
TEST(HttpResponse, default_response_code_should_be_unset)
{
HttpResponse response;
ASSERT_EQ(HttpResponse::Unset, response.getCode());
}
![Page 19: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/19.jpg)
IBM Software Group | Rational software
19Innovation for a smarter planet
The first mock (1)
class RestfulServer
{
virtual bool doesDirectoryExist(const std::string& name) = 0;
virtual bool doesResourceExist(const std::string& name) = 0;
};
class MockRestfulServer : public RestfulServer
{
MOCK_METHOD1(doesDirectoryExist,
bool(const std::string& name));
MOCK_METHOD1(doesResourceExist,
bool(const std::string& name));
};
![Page 20: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/20.jpg)
IBM Software Group | Rational software
20Innovation for a smarter planet
The first mock (2)TEST(JazzProxy_fileExists, should_return_true_if_directory_exists)
{
MockRestfulServer mockServer;
Proxy proxy(mockServer);
EXPECT_CALL(mockServer, doesDirectoryExist(_))
.WillOnce(Return(true));
EXPECT_CALL(mockServer, doesResourceExist(_))
.Times(0);
bool exists = false;
ASSERT_NO_THROW(proxy.fileExists(“myFolder", exists) );
ASSERT_TRUE(exists);
}
![Page 21: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/21.jpg)
IBM Software Group | Rational software
21Innovation for a smarter planet
Another Mock (1)HttpTimer::~HttpTimer()
{
if (theLogger.getLevel() >= LOG_LEVEL_WARNING)
theLogger.writeLn(“Timer: %d ms", stopClock());
}
class Logger
{
public:
virtual ~Logger();
// Operations for logging textual entries to a log file.
virtual unsigned getLevel() const = 0;
virtual void write(const char* fmt, ...) = 0;
virtual void writeLn(const char* fmt, ...) = 0;
};
![Page 22: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/22.jpg)
IBM Software Group | Rational software
22Innovation for a smarter planet
Another Mock (2)class MockLogger : public Logger
{
public:
MOCK_CONST_METHOD0(getLevel, unsigned int());
void write(const char* fmt, ...) {};
void writeLn(const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
DWORD clock = va_arg(ap, DWORD);
va_end(ap);
mockWriteLn(fmt, clock);
}
MOCK_METHOD2(mockWriteLn, void(const char*, DWORD));
};
![Page 23: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/23.jpg)
IBM Software Group | Rational software
23Innovation for a smarter planet
Another Mock (3)
TEST(HttpTimer, writes_to_logger_if_log_level_is_at_warning)
{
MockLogger testLogger;
EXPECT_CALL(testLogger, getLevel())
.WillOnce(Return(LOG_LEVEL_WARNING));
EXPECT_CALL(testLogger, mockWriteLn( _, _))
.Times(1);
HttpTimer timer(testLogger);
}
![Page 24: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/24.jpg)
IBM Software Group | Rational software
24Innovation for a smarter planet
Agenda Background
Unit Testing
Frameworks
Test & Mock: First Examples
Refactoring: Wrap Dependency
Refactoring: Extract Component
Refactoring: Non-Intrusive C Seam
Conclusions
Questions
![Page 25: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/25.jpg)
IBM Software Group | Rational software
25Innovation for a smarter planet
Wrap Dependency
CONTEXT
We want to test some legacy code
The legacy code has an ugly dependencyRequires inclusion of code we don’t want to test
SOLUTION
Create an interface that describes behaviour of dependency
Re-write call to inject dependency
In test code inject a test double
![Page 26: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/26.jpg)
IBM Software Group | Rational software
26Innovation for a smarter planet
Test Doubles
Dummy: never used – only passed around to fill parameter list
Stub: provides canned responses
Fake: has simplified implementation
Mock: object pre-programmed with expectations – the specification of calls they are expected to receive
“Test Double”: generic term for any of the above
![Page 27: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/27.jpg)
IBM Software Group | Rational software
27Innovation for a smarter planet
Code Under Test tree* openBaseline(tree *module, VersionId version)
{
tree *baseline = NULL;
…
BaselineId baselineId = DoorsServer::getInstance().findBaseline( module, version);
…
return baseline;
}
![Page 28: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/28.jpg)
IBM Software Group | Rational software
28Innovation for a smarter planet
Test The Defect
TEST(OpenBaseline, opening_a_baseline_with_default_version_should_throw)
{
tree myTree;
VersionId version;
ASSERT_THROWS_ANY(openBaseline(&myTree, version));
}
Won’t link without inclusion of DoorsServer
![Page 29: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/29.jpg)
IBM Software Group | Rational software
29Innovation for a smarter planet
Describe Behaviourclass Server
{
virtual BaselineId findBaseline(tree*, VersionId) = 0;
}
class DoorsServer : public Server
{
…
BaselineId findBaseline(tree*, VersionId);
…
}
![Page 30: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/30.jpg)
IBM Software Group | Rational software
30Innovation for a smarter planet
Refactor Code Under Test tree* openBaseline(
Server& server,tree *module, VersionId version)
{
tree *baseline = NULL;
…
BaselineId baselineId = server.findBaseline( module, version);
…
return baseline;
}
![Page 31: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/31.jpg)
IBM Software Group | Rational software
31Innovation for a smarter planet
Modify the Testclass TestServer : public Server{
BaselineId findBaseline(tree*, VersionId) { return BaselineId(); }
};
TEST(OpenBaseline, opening_a_baseline_with_default_version_should_throw)
{
TestServer server;
tree myTree;
VersionId version;
ASSERT_THROWS_ANY(
openBaseline(server, &myTree, version));
}
![Page 32: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/32.jpg)
IBM Software Group | Rational software
32Innovation for a smarter planet
After the test passes Modify all call sites
openBaseline(t, version);
becomes
openBaseline(DoorsServer::getInstance(), t, version);
Add more methods to the interface as necessaryConsider cohesion
Don’t mindlessly create a monster interface
A similar result can be achieved without introducing an interface at all.
![Page 33: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/33.jpg)
IBM Software Group | Rational software
33Innovation for a smarter planet
Agenda
Background
Unit Testing
Frameworks
Test & Mock: First Examples
Refactoring: Wrap Dependency
Refactoring: Extract Component
Refactoring: Non-Intrusive C Seam
Conclusions
Questions
![Page 34: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/34.jpg)
IBM Software Group | Rational software
34Innovation for a smarter planet
Extract Component
CONTEXT
All our code has dependency on ‘utility’ functionality
Some ‘utility’ functionality has dependencies on core application
Leads to linking test with entire codebase
SOLUTION
Build ‘utility’ functionality as independent component used by application and tests
![Page 35: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/35.jpg)
IBM Software Group | Rational software
35Innovation for a smarter planet
Tests
Application
Before RefactoringDuring Unit Test
Interesting Code
Application
While App Executes
main
Interesting Code
![Page 36: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/36.jpg)
IBM Software Group | Rational software
36Innovation for a smarter planet
Simple Extraction Not Enough
Interesting Code
UtilityFunctionality
Application
main Utility code still dependent on app
No build time improvementTests
![Page 37: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/37.jpg)
IBM Software Group | Rational software
37Innovation for a smarter planet
Break DependencyPROCEDURE
Create new interface(s) for dependencies of ‘utility’
class UserNotifier { virtual void notify(char*) =0; };
Implement interface in application code
class DoorsUserNotifier : public UserNotifier {
virtual void notify(char*) { … }
};
Inject implementation of interface into ‘utility’ at initialisation
DoorsUserNotifier userNotifier;
utility.setUserNotifier(userNotifier);
![Page 38: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/38.jpg)
IBM Software Group | Rational software
38Innovation for a smarter planet
Modify Utility Code Interface registration
void Utility::setUserNotifier(UserNotifier notifier) {
userNotifier = notifier;
}
Modify call sites in ‘utility’ to use injected interface
If no implementation present (i.e. during unit testing), then use of interface does nothing
void Utility::notifyUser(char* message) {
if (!userNotifier.isNull())
userNotifier->notify(message);
}
![Page 39: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/39.jpg)
IBM Software Group | Rational software
39Innovation for a smarter planet
Full extraction
Utility code is used in many places
All test projects will depend on it
Package as shared libraryReduces build times
Helps keep contracts explicit
![Page 40: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/40.jpg)
IBM Software Group | Rational software
40Innovation for a smarter planet
Tests
After RefactoringDuring Unit Test
UtilityFunctionality
<<interface>>Mock
Dependencies
Application
Interesting Code
UtilityFunctionality
<<interface>>Application
Dependencies
Application
While App Executes
main
Interesting Code
1. Inject Dependencies
2. Run Application
![Page 41: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/41.jpg)
IBM Software Group | Rational software
41Innovation for a smarter planet
Agenda
Background
Unit Testing
Frameworks
Test & Mock: First Examples
Refactoring: Wrap Dependency
Refactoring: Extract Component
Refactoring: Non-Intrusive C Seam
Conclusions
Questions
![Page 42: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/42.jpg)
IBM Software Group | Rational software
42Innovation for a smarter planet
Original code// startup.c
void startup()
{
db_initialize();
…
}
// database.h
extern void db_initialize();
// database.c
void db_initialize()
{
…
}
db_initialize
startup
![Page 43: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/43.jpg)
IBM Software Group | Rational software
43Innovation for a smarter planet
How to unit test?
We want to test the startup method, but we don’t want to use the database
How can we test startup without calling db_initialize?
Use preprocessor
Use runtime switch
Supply ‘mock’ database object
The Mocking solution is the most versatile… but also the most complex
![Page 44: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/44.jpg)
IBM Software Group | Rational software
44Innovation for a smarter planet
Non-Intrusive C Seam
CONTEXT
We want to replace some existing functionality
The functionality is implemented by procedural C code with no well defined interface
We don’t want to modify the ‘client’ code that uses this functionality
SOLUTION
Create/extract an interface
Use C++ namespaces to silently redirect client calls through a factory/shim
![Page 45: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/45.jpg)
IBM Software Group | Rational software
45Innovation for a smarter planet
Create new interface
// Database.h
class Database
{
virtual void initialize() = 0;
….
};
db_initialize
startup
Database
![Page 46: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/46.jpg)
IBM Software Group | Rational software
46Innovation for a smarter planet
Move legacy code into namespace// database.h
namespace Legacy
{
extern void db_initialize();
}
// database.c
namespace Legacy
{
void db_initialize()
{
…
}
}
startup db_initialize
Global namespaceLegacy namespace
Database
![Page 47: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/47.jpg)
IBM Software Group | Rational software
47Innovation for a smarter planet
Implement the new interface
// LegacyDatabase.h
class LegacyDatabase : public Database
{
void initialize();
};
// LegacyDatabase.cpp
void LegacyDatabase::initialize()
{
Legacy::db_initialize();
}
startup
Global namespace
db_initialize
Database
LegacyDatabase
Legacy namespace
![Page 48: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/48.jpg)
IBM Software Group | Rational software
48Innovation for a smarter planet
Create a shim
// shim.h
extern void db_initialize();
// shim.cpp
void db_initialize()
{
Factory::getDatabase()
.initialize();
}
startup db_initialize
shim
Database
LegacyDatabase
Global namespaceLegacy namespace
![Page 49: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/49.jpg)
IBM Software Group | Rational software
49Innovation for a smarter planet
Redirect client to shim
// startup.c
#include “shim.h”
void startup()
{
db_initialize();
…
}
startup db_initialize
shim
Database
LegacyDatabase
Global namespaceLegacy namespace
![Page 50: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/50.jpg)
IBM Software Group | Rational software
50Innovation for a smarter planet
Schematic of transformation
db_initialize
startup
Before After
Global namespace
startup db_initialize
shim
Database
LegacyDatabase
Global namespaceLegacy namespace
![Page 51: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/51.jpg)
IBM Software Group | Rational software
51Innovation for a smarter planet
What have we achieved?
Extracted an interface with minimal changes to client code
Original invocation now calls shim code
Shim uses factory to select implementation
Factory can return a fake or mock object
Legacy implementation behaves exactly as before
Code can be unit tested independently
Alternative implementations of interface can be provided
![Page 52: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/52.jpg)
IBM Software Group | Rational software
52Innovation for a smarter planet
Agenda
Background
Unit Testing
Frameworks
Test & Mock: First Examples
Refactoring: Wrap Dependency
Refactoring: Extract Component
Refactoring: Non-Intrusive C Seam
Conclusions
Questions
![Page 53: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/53.jpg)
IBM Software Group | Rational software
53Innovation for a smarter planet
Are we there yet?
Move to iterative development
All new/modified code to have unit tests
All unit tests to be run every build
Develop “Whole Team” approachAutomated acceptance tests written by test & dev
Test to pick up nightly builds
Align with Rational toolset
![Page 54: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/54.jpg)
IBM Software Group | Rational software
54Innovation for a smarter planet
Conclusions
New skills/techniques to learnUnit testing is hardWriting testable code is hardBooks are not enough… practice needed
Up-front refactoring costLots of hard work making legacy code testableOne step at a time
Build times are important to developersBut other metrics are equally interesting
![Page 55: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/55.jpg)
IBM Software Group | Rational software
55Innovation for a smarter planet
Musical trivia
You can lead a horse to water,
But you can’t make it drink
Think about it,
All you’ve got to do is think
about it
There’s no cure.
- The Beast, The Only Ones
![Page 56: ® IBM Software Group © 2009 IBM Corporation Innovation for a smarter planet Stopping the rot Putting legacy C++ under test Seb Rose ACCU 2011](https://reader030.vdocuments.net/reader030/viewer/2022032414/56649ee65503460f94bf67c6/html5/thumbnails/56.jpg)
IBM Software Group | Rational software
56Innovation for a smarter planet
Agenda
Background
Unit Testing
Frameworks
Test & Mock: First Examples
Refactoring: Wrap Dependency
Refactoring: Extract Component
Refactoring: Non-Intrusive C Seam
Conclusions
Questions