generating characterization tests for legacy code
DESCRIPTION
Lightning talk from JavaZone 2010 on generating characterization tests for legacy code.TRANSCRIPT
![Page 1: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/1.jpg)
Generating Characterization Tests for Legacy Code
Jonas Follesø (@follesoe)
JavaZone 2010, 09. September
![Page 2: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/2.jpg)
Huge methods (~3000+ lines)
![Page 3: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/3.jpg)
Dav
e &
Kar
in h
ttp:
//w
ww
.flic
kr.c
om/p
hoto
s/dn
k_uk
/352
5103
502/
~50 slow integration tests
![Page 4: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/4.jpg)
How the development team felt...
![Page 5: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/5.jpg)
What they needed
![Page 6: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/6.jpg)
What I read
![Page 7: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/7.jpg)
Fras
er S
peirs
htt
p://
ww
w.fl
ickr
.com
/pho
tos/
fras
ersp
eirs
/339
5595
360/
Legacy code is code without tests. Code without tests is bad code.
-Michael C. Feathers
![Page 8: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/8.jpg)
A characterization test is test that characterizes the actual behavior of a piece of code.
It acts as a change detector, protecting legacy code form unintended changes
![Page 9: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/9.jpg)
public double Calc(double inv, double rt, int y){ double ret = 0; for (int i = 1; i <= y; i++) { ret = inv * Math.Pow(1.0 + rt / 100.0, i); } return ret;}
![Page 10: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/10.jpg)
[TestMethod]public void Calc_characterization(){ var calc = new CalcUtil(); double result = calc.Calc(10000, 10, 10);
Assert.AreEqual(42.0, result); }
![Page 11: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/11.jpg)
Assert.AreEqual failed. Expected:<42>.
Actual:<25937.424601>.
![Page 12: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/12.jpg)
[TestMethod]public void Calc_characterization(){ var calc = new CalcUtil(); double result = calc.Calc(10000, 10, 10);
Assert.AreEqual(42, result); Assert.AreEqual(25937.424601, result); }
![Page 13: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/13.jpg)
Test run completed. Results 1/1 passed.
![Page 14: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/14.jpg)
public double CalculateCompoundInterest(double investment, double interest, int
years){ double projectedValue = 0.0; for (int year = 1; year <= years; year++) { projectedValue = investment *
Math.Pow(1.0 + interest / 100.0, year); }
return projectedValue;}
![Page 15: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/15.jpg)
Fras
er S
peirs
htt
p://
ww
w.fl
ickr
.com
/pho
tos/
fras
ersp
eirs
/339
5599
536/
…A pinch point is a natural encapsulation boundary. When you find a pinch point, you’ve found a narrow funnel for all the effects of a large piece of code…
-Michael C. Feathers
![Page 16: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/16.jpg)
~85% code coverage
http:
//w
ww
.flic
kr.c
om/p
hoto
s/sh
utter
cat7
/713
1862
11/
![Page 17: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/17.jpg)
// This method is the "pinch point" we want to test...public object CalculateSomething(object someParameter){ // 1) Record input parameters... // 2) Do the work... // 3) Write parameters and return value to XML file.}
![Page 18: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/18.jpg)
[TestMethod]public void CalculateSomething_test1(){ Run("Recordings/CalculateSomething1.xml");}
[TestMethod]public void CalculateSomething_test2(){ Run("Recordings/CalculateSomething2.xml");}
public void Run(string filename){ // Load input parameters from XML file // Load return value from XML file // Call method under test // Use reflection to compare actual vs. recorded}
![Page 19: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/19.jpg)
~300 fast characterization tests
![Page 20: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/20.jpg)
How can we reuse this?
![Page 21: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/21.jpg)
http://follesoe.github.com/BlackBoxRecorder
![Page 22: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/22.jpg)
[Recording]
![Page 23: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/23.jpg)
[Dependency]
![Page 24: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/24.jpg)
[Recording]public List<EmployeeEntity> GetMakingMoreThan(double salary){ var dal = new EmployeeDAL();
var employees = dal.GetAllEmployees();
return employees.Where(e => e.Salary > salary).ToList();}
![Page 25: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/25.jpg)
[Dependency]public class EmployeeDAL{ public List<EmployeeEntity> GetAllEmployees() { // Calls to database... }}
![Page 26: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/26.jpg)
<Recording> <Name>GetEmployeesMakingMoreThan_salary</Name> <Method>GetEmployeesMakingMoreThan</Method> <Type><![CDATA[BlackBox.Demo.App.SimpleAnemic.EmployeeBL]]></Type> <InputParameters> <Parameter> <Name>salary</Name> <Type><![CDATA[System.Double]]></Type> <Value><![CDATA[5000]]></Value> </Parameter> </InputParameters>
<Return> <Type><![CDATA[List<BlackBox.Demo.App.SimpleAnemic.EmployeeEntity>]]></Type> <Value><![CDATA[XML representation of employees retruned from method]]></Value> </Return>
<Dependencies> <Dependency> <Type><![CDATA[BlackBox.Demo.App.SimpleAnemic.EmployeeDAL]]></Type> <Method> <Name>GetAllEmployees</Name> <ReturnValues> <ReturnValue> <Value><![CDATA[XML representation of all employees returned from db]]><Value> </ReturnValue> </ReturnValues> </Method> </Dependency> </Dependencies>
</Recording>
![Page 27: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/27.jpg)
[TestMethod]public void GetEmployeesMakingMoreThan_salary(){ Run(@"GetEmployeesMakingMoreThan_salary.xml");}
![Page 28: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/28.jpg)
http://github.com/oc/jackbox
![Page 29: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/29.jpg)
@Recordingpublic int exampleMethod(int parameter, int parameter2) { return parameter + parameter2;}
@Dependencypublic String invokedMethodOnDependency(String argument) { return argument.toUpperCase();}
![Page 30: Generating characterization tests for legacy code](https://reader036.vdocuments.us/reader036/viewer/2022062312/554fb4eab4c905ad218b54ac/html5/thumbnails/30.jpg)
BEKK CONSULTING ASSKUR 39, VIPPETANGEN. P.O. BOX 134 SENTRUM, 0102 OSLO, NORWAY.
WWW.BEKK.NO
Jonas FollesøSenior Consultant
+47 977 [email protected] /