SlideShare a Scribd company logo
1 of 31
Download to read offline
Unit testing
legacy code
Lars Thorup
ZeaLake Software Consulting
May, 2014
Who is Lars Thorup?
● Software developer/architect
● JavaScript, C#
● Test Driven Development
● Continuous Integration
● Coach: Teaching TDD and
continuous integration
● Founder of ZeaLake
● @larsthorup
The problems with legacy code
● No tests
● The code probably works...
● Hard to refactor
● Will the code still work?
● Hard to extend
● Need to change the code...
● The code owns us :(
● Did our investment turn sour?
How do tests bring us back in control?
● A refactoring improves the design without changing
behavior
● Tests ensure that behavior is not
accidentally changed
● Without tests, refactoring is scary
● and with no refactoring, the design decays over time
● With tests, we have the courage to refactor
● so we continually keep our design healthy
What comes first: the test or the refactoring?
How do we get to sustainable legacy code?
● Make it easy to add characterization tests
● Have good unit test coverage for important areas
● Don't worry about code you don't need to change
● Test-drive all new code
● Now we own the code :)
Making legacy code sustainable
● Select an important area
● Driven by change requests
● Add characterization tests
● Make code testable
● Refactor the code
● Add unit tests
● Remove characterization tests
● Small steps
Characterization tests
● Characterize current
behavior
● Integration tests
● Either high level unit tests
● Or end-to-end tests
● Don't change existing code
● Faulty behavior = current
behavior: don't change it!
● Make a note to fix later
● Test at a level that makes it
easy
● The characterization tests
are throw-aways
● Demo:
● Web service test: VoteMedia
● End-to-end browser test:
entrylist.demo.test.js
Make code testable
● Avoid large methods
● They require a ton of setup
● They require lots of scenarios to cover all variations
● Avoid outer scope dependencies
● They require you to test at a higher level
● Avoid external dependencies
● ... a ton of setup
● They slow you down
Refactor the code
● Add interface
● Inject a mock instead of the
real thing
● Easier setup
● Infinitely faster
Notifier
EmailSvc
IEmailSvc
EmailSvcStub
NotifierTest
● Extract method
● Split up large methods
● To simplify unit testing single
behaviors
● Demo:
VoteWithVideo_Vimas
● Add parameter
● Pass in outer-scope
dependencies
● The tests can pass in their
own dummy values
● Demo:
Entry.renderResponse
Add unit tests
● Now that the code is testable...
● Write unit tests for you small methods
● Pass in dummy values for parameters
● Mock dependencies
● Rinse and repeat...
Remove the characterization tests
● When unit test code coverage is good enough
● To speed up feedback
● To avoid test duplication
Small steps - elephant carpaccio
● Any big refactoring...
● ...can be done in small steps
● Demo: Security system (see slide 19 through 31)
Test-drive all new code
● Easy, now that unit testing tools are in place
Failing
test
Succeeding
test
Good
design Refactor
Test
Intention
Think, talk
Code
Making legacy code sustainable
● Select an important area
● Driven by change requests
● Add characterization tests
● Make code testable
● Refactor the code
● Add unit tests
● Remove characterization tests
● Small steps
It's not hard - now go do it!
● This is hard
● SQL query efficiency
● Cache invalidation
● Scalability
● Pixel perfect rendering
● Cross-browser compatibility
● Indexing strategies
● Security
● Real time media streaming
● 60fps gaming with HTML5
● ... and robust Selenium tests!
● This is not hard
● Refactoring
● Unit testing
● Dependency injection
● Automated build and test
● Continuous Integration
● Fast feedback will make
you more productive
● ... and more happy
A big refactoring is needed...
Avoid feature branches
● For features as well as large refactorings
● Delayed integration
● Increases risk
● Increases cost
Use feature toggles
● Any big refactoring...
● ...can be done in small
steps
● Allows us to keep
development on
trunk/master
● Drastically lowering the risk
● Commit after every step
● At most a couple of hours
Security example
● Change the code from the
old security system
● To our new extended
security model
interface IPrivilege
{
bool HasRole(Role);
}
class Permission
{
bool IsAdmin();
}
Step 0: existing implementation
● Code instantiates
Legacy.Permission
● and calls methods like
permission.IsAdmin()
● ...all over the place
● We want to replace this
with a new security system
void SomeController()
{
var p = new Permission();
if (p.IsAdmin())
{
...
}
}
Step 1: New security implementation
● Implements an interface
● This can be committed
gradually
interface IPrivilege
{
bool HasRole(Role);
}
class Privilege : IPrivilege
{
bool HasRole(Role r)
{
...
}
}
Step 2: Wrap the old implementation
● Create
Security.LegacyPermission
● Implement new interface
● Wrap existing
implementation
● Expose existing
implementation
class LegacyPermission : IPrivilege
{
LegacyPermission(Permission p)
{
this.p = p;
}
bool HasRole(Role r)
{
if (r == Role.Admin)
return p.IsAdmin();
return false;
}
Permission Permission
{
get: { return p; }
}
private Permission p;
}
Step 3: Factory
● Create a factory
● Have it return the new
implementation
● Unless directed to return
the wrapped old one
class PrivilegeFactory
{
IPrivilege Create(bool old=true)
{
if(!old)
{
return new Privilege();
}
return new LegacyPermission();
}
}
Step 4: Test compatibility
● Write tests
● Run all tests against both
implementations
● Iterate until the new
implementation has a
satisfactory level of
backwards compatibility
● This can be committed
gradually
[TestCase(true)]
[TestCase(false)]
void HasRole(bool old)
{
// given
var f = new PrivilegeFactory();
var p = f.Create(old);
// when
var b = p.HasRole(Role.Admin);
// then
Assert.That(b, Is.True);
}
Step 5: Dumb migration
● Replace all uses of the old
implementation with the
new wrapper
● Immediately use the
exposed old
implementation
● This can be committed
gradually
void SomeController()
{
var priv = f.Create(true)
as LegacyPermission;
var p = priv.Permission;
if (p.IsAdmin())
{
...
}
}
Step 6: Actual migration
● Rewrite code to use the
new implementation
instead of the exposed old
implementation
● This can be committed
gradually
void SomeController()
{
var p = f.Create(true);
if (p.HasRole(Role.Admin)
{
...
}
}
Step 7: Verify migration is code complete
● Delete the property
exposing the old
implementation
● Go back to previous step if
the code does not compile
● Note: at this point the code
is still using the old
implementation
everywhere!
class LegacyPermission : IPrivilege
{
...
// Permission Permission
// {
// get: { return p; }
// }
private Permission p;
}
Step 8: Verify migration works
● Allow QA to explicitly switch
to the new implementation
● We now have a Feature
Toggle
● Do thorough exploratory
testing with the new
implementation
● If unintented behavior is
found, go back to step 4
and add a new test that
fails for this reason, fix the
issue and repeat
class PrivilegeFactory
{
IPrivilege Create(bool old=true)
{
var UseNew = %UseNew%;
if(!old || UseNew)
{
return new Privilege();
}
return new LegacyPermission();
}
}
Step 9: Complete migration
● Always use the new
implementation
● Mark the old
implementation as
Obsolete to prevent new
usages
class PrivilegeFactory
{
IPrivilege Create()
{
return new Privilege();
}
}
[Obsolete]
class Permission
{
...
}
Step 10: Clean up
● After proper validation in
production, delete the old
implementation

More Related Content

What's hot

VT.NET 20160411: An Intro to Test Driven Development (TDD)
VT.NET 20160411: An Intro to Test Driven Development (TDD)VT.NET 20160411: An Intro to Test Driven Development (TDD)
VT.NET 20160411: An Intro to Test Driven Development (TDD)Rob Hale
 
TDD And Refactoring
TDD And RefactoringTDD And Refactoring
TDD And RefactoringNaresh Jain
 
iOS Test-Driven Development
iOS Test-Driven DevelopmentiOS Test-Driven Development
iOS Test-Driven DevelopmentPablo Villar
 
TDD - Test Driven Development
TDD - Test Driven DevelopmentTDD - Test Driven Development
TDD - Test Driven DevelopmentTung Nguyen Thanh
 
Test driven development and unit testing with examples in C++
Test driven development and unit testing with examples in C++Test driven development and unit testing with examples in C++
Test driven development and unit testing with examples in C++Hong Le Van
 
An Introduction to Test Driven Development
An Introduction to Test Driven Development An Introduction to Test Driven Development
An Introduction to Test Driven Development CodeOps Technologies LLP
 
Unit Testing in Action - C#, NUnit, and Moq
Unit Testing in Action - C#, NUnit, and MoqUnit Testing in Action - C#, NUnit, and Moq
Unit Testing in Action - C#, NUnit, and MoqXPDays
 
Refactoring - An Introduction
Refactoring - An IntroductionRefactoring - An Introduction
Refactoring - An IntroductionGiorgio Vespucci
 
Introduction to TDD (Test Driven development) - Ahmed Shreef
Introduction to TDD (Test Driven development) - Ahmed ShreefIntroduction to TDD (Test Driven development) - Ahmed Shreef
Introduction to TDD (Test Driven development) - Ahmed ShreefAhmed Shreef
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven DevelopmentConsulthinkspa
 
Agile Programming Systems # TDD intro
Agile Programming Systems # TDD introAgile Programming Systems # TDD intro
Agile Programming Systems # TDD introVitaliy Kulikov
 
Dependency Injection in iOS
Dependency Injection in iOSDependency Injection in iOS
Dependency Injection in iOSPablo Villar
 
Unit Testing Fundamentals
Unit Testing FundamentalsUnit Testing Fundamentals
Unit Testing FundamentalsRichard Paul
 
Unit Test + Functional Programming = Love
Unit Test + Functional Programming = LoveUnit Test + Functional Programming = Love
Unit Test + Functional Programming = LoveAlvaro Videla
 
Working with Legacy Code
Working with Legacy CodeWorking with Legacy Code
Working with Legacy CodeEyal Golan
 
Roy Osherove on Unit Testing Good Practices and Horrible Mistakes
Roy Osherove on Unit Testing Good Practices and Horrible MistakesRoy Osherove on Unit Testing Good Practices and Horrible Mistakes
Roy Osherove on Unit Testing Good Practices and Horrible MistakesRoy Osherove
 
Testing Legacy Rails Apps
Testing Legacy Rails AppsTesting Legacy Rails Apps
Testing Legacy Rails AppsRabble .
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy CodeRowan Merewood
 
Software Quality via Unit Testing
Software Quality via Unit TestingSoftware Quality via Unit Testing
Software Quality via Unit TestingShaun Abram
 

What's hot (20)

VT.NET 20160411: An Intro to Test Driven Development (TDD)
VT.NET 20160411: An Intro to Test Driven Development (TDD)VT.NET 20160411: An Intro to Test Driven Development (TDD)
VT.NET 20160411: An Intro to Test Driven Development (TDD)
 
TDD And Refactoring
TDD And RefactoringTDD And Refactoring
TDD And Refactoring
 
iOS Test-Driven Development
iOS Test-Driven DevelopmentiOS Test-Driven Development
iOS Test-Driven Development
 
TDD - Test Driven Development
TDD - Test Driven DevelopmentTDD - Test Driven Development
TDD - Test Driven Development
 
Test driven development and unit testing with examples in C++
Test driven development and unit testing with examples in C++Test driven development and unit testing with examples in C++
Test driven development and unit testing with examples in C++
 
An Introduction to Test Driven Development
An Introduction to Test Driven Development An Introduction to Test Driven Development
An Introduction to Test Driven Development
 
Unit Testing in Action - C#, NUnit, and Moq
Unit Testing in Action - C#, NUnit, and MoqUnit Testing in Action - C#, NUnit, and Moq
Unit Testing in Action - C#, NUnit, and Moq
 
Refactoring - An Introduction
Refactoring - An IntroductionRefactoring - An Introduction
Refactoring - An Introduction
 
Introduction to TDD (Test Driven development) - Ahmed Shreef
Introduction to TDD (Test Driven development) - Ahmed ShreefIntroduction to TDD (Test Driven development) - Ahmed Shreef
Introduction to TDD (Test Driven development) - Ahmed Shreef
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Development
 
Agile Programming Systems # TDD intro
Agile Programming Systems # TDD introAgile Programming Systems # TDD intro
Agile Programming Systems # TDD intro
 
Dependency Injection in iOS
Dependency Injection in iOSDependency Injection in iOS
Dependency Injection in iOS
 
Unit Testing Fundamentals
Unit Testing FundamentalsUnit Testing Fundamentals
Unit Testing Fundamentals
 
Unit Test + Functional Programming = Love
Unit Test + Functional Programming = LoveUnit Test + Functional Programming = Love
Unit Test + Functional Programming = Love
 
Working with Legacy Code
Working with Legacy CodeWorking with Legacy Code
Working with Legacy Code
 
Roy Osherove on Unit Testing Good Practices and Horrible Mistakes
Roy Osherove on Unit Testing Good Practices and Horrible MistakesRoy Osherove on Unit Testing Good Practices and Horrible Mistakes
Roy Osherove on Unit Testing Good Practices and Horrible Mistakes
 
Testing Legacy Rails Apps
Testing Legacy Rails AppsTesting Legacy Rails Apps
Testing Legacy Rails Apps
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy Code
 
TDD & BDD
TDD & BDDTDD & BDD
TDD & BDD
 
Software Quality via Unit Testing
Software Quality via Unit TestingSoftware Quality via Unit Testing
Software Quality via Unit Testing
 

Similar to Unit testing legacy code

Test and Behaviour Driven Development (TDD/BDD)
Test and Behaviour Driven Development (TDD/BDD)Test and Behaviour Driven Development (TDD/BDD)
Test and Behaviour Driven Development (TDD/BDD)Lars Thorup
 
Writing Tests with the Unity Test Framework
Writing Tests with the Unity Test FrameworkWriting Tests with the Unity Test Framework
Writing Tests with the Unity Test FrameworkPeter Kofler
 
High Performance Software Engineering Teams
High Performance Software Engineering TeamsHigh Performance Software Engineering Teams
High Performance Software Engineering TeamsLars Thorup
 
Yet Another Continuous Integration Story
Yet Another Continuous Integration StoryYet Another Continuous Integration Story
Yet Another Continuous Integration StoryAnton Serdyuk
 
A la découverte des google/test (aka gtest)
A la découverte des google/test (aka gtest)A la découverte des google/test (aka gtest)
A la découverte des google/test (aka gtest)Thierry Gayet
 
Test driven development - Zombie proof your code
Test driven development - Zombie proof your codeTest driven development - Zombie proof your code
Test driven development - Zombie proof your codePascal Larocque
 
Keeping code clean
Keeping code cleanKeeping code clean
Keeping code cleanBrett Child
 
Android Test Driven Development & Android Unit Testing
Android Test Driven Development & Android Unit TestingAndroid Test Driven Development & Android Unit Testing
Android Test Driven Development & Android Unit Testingmahmoud ramadan
 
High ROI Testing in Angular.pptx
High ROI Testing in Angular.pptxHigh ROI Testing in Angular.pptx
High ROI Testing in Angular.pptxChristian Lüdemann
 
North Virginia Coldfusion User Group Meetup - Testbox - July 19th 2017
North Virginia Coldfusion User Group Meetup - Testbox - July 19th 2017North Virginia Coldfusion User Group Meetup - Testbox - July 19th 2017
North Virginia Coldfusion User Group Meetup - Testbox - July 19th 2017Ortus Solutions, Corp
 
Expedia 3x3 presentation
Expedia 3x3 presentationExpedia 3x3 presentation
Expedia 3x3 presentationDrew Hannay
 
Test all the things! Automated testing with Drupal 8
Test all the things! Automated testing with Drupal 8Test all the things! Automated testing with Drupal 8
Test all the things! Automated testing with Drupal 8Sam Becker
 
Indy meetup#7 effective unit-testing-mule
Indy meetup#7 effective unit-testing-muleIndy meetup#7 effective unit-testing-mule
Indy meetup#7 effective unit-testing-muleikram_ahamed
 
Introduction to Test Automation
Introduction to Test AutomationIntroduction to Test Automation
Introduction to Test AutomationPekka Klärck
 
Unit Testing and TDD 2017
Unit Testing and TDD 2017Unit Testing and TDD 2017
Unit Testing and TDD 2017Xavi Hidalgo
 
Bootstrapping Quality
Bootstrapping QualityBootstrapping Quality
Bootstrapping QualityMichael Roufa
 
Put "fast" back in "fast feedback"
Put "fast" back in "fast feedback"Put "fast" back in "fast feedback"
Put "fast" back in "fast feedback"Lars Thorup
 
Software Testing
Software TestingSoftware Testing
Software TestingAndrew Wang
 
Cypress Best Pratices for Test Automation
Cypress Best Pratices for Test AutomationCypress Best Pratices for Test Automation
Cypress Best Pratices for Test AutomationKnoldus Inc.
 

Similar to Unit testing legacy code (20)

Test and Behaviour Driven Development (TDD/BDD)
Test and Behaviour Driven Development (TDD/BDD)Test and Behaviour Driven Development (TDD/BDD)
Test and Behaviour Driven Development (TDD/BDD)
 
Writing Tests with the Unity Test Framework
Writing Tests with the Unity Test FrameworkWriting Tests with the Unity Test Framework
Writing Tests with the Unity Test Framework
 
High Performance Software Engineering Teams
High Performance Software Engineering TeamsHigh Performance Software Engineering Teams
High Performance Software Engineering Teams
 
Yet Another Continuous Integration Story
Yet Another Continuous Integration StoryYet Another Continuous Integration Story
Yet Another Continuous Integration Story
 
A la découverte des google/test (aka gtest)
A la découverte des google/test (aka gtest)A la découverte des google/test (aka gtest)
A la découverte des google/test (aka gtest)
 
Ui Testing with Ghost Inspector
Ui Testing with Ghost InspectorUi Testing with Ghost Inspector
Ui Testing with Ghost Inspector
 
Test driven development - Zombie proof your code
Test driven development - Zombie proof your codeTest driven development - Zombie proof your code
Test driven development - Zombie proof your code
 
Keeping code clean
Keeping code cleanKeeping code clean
Keeping code clean
 
Android Test Driven Development & Android Unit Testing
Android Test Driven Development & Android Unit TestingAndroid Test Driven Development & Android Unit Testing
Android Test Driven Development & Android Unit Testing
 
High ROI Testing in Angular.pptx
High ROI Testing in Angular.pptxHigh ROI Testing in Angular.pptx
High ROI Testing in Angular.pptx
 
North Virginia Coldfusion User Group Meetup - Testbox - July 19th 2017
North Virginia Coldfusion User Group Meetup - Testbox - July 19th 2017North Virginia Coldfusion User Group Meetup - Testbox - July 19th 2017
North Virginia Coldfusion User Group Meetup - Testbox - July 19th 2017
 
Expedia 3x3 presentation
Expedia 3x3 presentationExpedia 3x3 presentation
Expedia 3x3 presentation
 
Test all the things! Automated testing with Drupal 8
Test all the things! Automated testing with Drupal 8Test all the things! Automated testing with Drupal 8
Test all the things! Automated testing with Drupal 8
 
Indy meetup#7 effective unit-testing-mule
Indy meetup#7 effective unit-testing-muleIndy meetup#7 effective unit-testing-mule
Indy meetup#7 effective unit-testing-mule
 
Introduction to Test Automation
Introduction to Test AutomationIntroduction to Test Automation
Introduction to Test Automation
 
Unit Testing and TDD 2017
Unit Testing and TDD 2017Unit Testing and TDD 2017
Unit Testing and TDD 2017
 
Bootstrapping Quality
Bootstrapping QualityBootstrapping Quality
Bootstrapping Quality
 
Put "fast" back in "fast feedback"
Put "fast" back in "fast feedback"Put "fast" back in "fast feedback"
Put "fast" back in "fast feedback"
 
Software Testing
Software TestingSoftware Testing
Software Testing
 
Cypress Best Pratices for Test Automation
Cypress Best Pratices for Test AutomationCypress Best Pratices for Test Automation
Cypress Best Pratices for Test Automation
 

More from Lars Thorup

100 tests per second - 40 releases per week
100 tests per second - 40 releases per week100 tests per second - 40 releases per week
100 tests per second - 40 releases per weekLars Thorup
 
SQL or NoSQL - how to choose
SQL or NoSQL - how to chooseSQL or NoSQL - how to choose
SQL or NoSQL - how to chooseLars Thorup
 
Super fast end-to-end-tests
Super fast end-to-end-testsSuper fast end-to-end-tests
Super fast end-to-end-testsLars Thorup
 
Extreme Programming - to the next-level
Extreme Programming - to the next-levelExtreme Programming - to the next-level
Extreme Programming - to the next-levelLars Thorup
 
Advanced Javascript Unit Testing
Advanced Javascript Unit TestingAdvanced Javascript Unit Testing
Advanced Javascript Unit TestingLars Thorup
 
Advanced QUnit - Front-End JavaScript Unit Testing
Advanced QUnit - Front-End JavaScript Unit TestingAdvanced QUnit - Front-End JavaScript Unit Testing
Advanced QUnit - Front-End JavaScript Unit TestingLars Thorup
 
Database Schema Evolution
Database Schema EvolutionDatabase Schema Evolution
Database Schema EvolutionLars Thorup
 
Advanced Jasmine - Front-End JavaScript Unit Testing
Advanced Jasmine - Front-End JavaScript Unit TestingAdvanced Jasmine - Front-End JavaScript Unit Testing
Advanced Jasmine - Front-End JavaScript Unit TestingLars Thorup
 
Javascript unit testing with QUnit and Sinon
Javascript unit testing with QUnit and SinonJavascript unit testing with QUnit and Sinon
Javascript unit testing with QUnit and SinonLars Thorup
 
Continuous Integration for front-end JavaScript
Continuous Integration for front-end JavaScriptContinuous Integration for front-end JavaScript
Continuous Integration for front-end JavaScriptLars Thorup
 
Automated Performance Testing
Automated Performance TestingAutomated Performance Testing
Automated Performance TestingLars Thorup
 
Elephant Carpaccio
Elephant CarpaccioElephant Carpaccio
Elephant CarpaccioLars Thorup
 
Automated Testing for Embedded Software in C or C++
Automated Testing for Embedded Software in C or C++Automated Testing for Embedded Software in C or C++
Automated Testing for Embedded Software in C or C++Lars Thorup
 
Unit Testing in JavaScript with MVC and QUnit
Unit Testing in JavaScript with MVC and QUnitUnit Testing in JavaScript with MVC and QUnit
Unit Testing in JavaScript with MVC and QUnitLars Thorup
 
Introduction to Automated Testing
Introduction to Automated TestingIntroduction to Automated Testing
Introduction to Automated TestingLars Thorup
 

More from Lars Thorup (16)

100 tests per second - 40 releases per week
100 tests per second - 40 releases per week100 tests per second - 40 releases per week
100 tests per second - 40 releases per week
 
SQL or NoSQL - how to choose
SQL or NoSQL - how to chooseSQL or NoSQL - how to choose
SQL or NoSQL - how to choose
 
Super fast end-to-end-tests
Super fast end-to-end-testsSuper fast end-to-end-tests
Super fast end-to-end-tests
 
Extreme Programming - to the next-level
Extreme Programming - to the next-levelExtreme Programming - to the next-level
Extreme Programming - to the next-level
 
Advanced Javascript Unit Testing
Advanced Javascript Unit TestingAdvanced Javascript Unit Testing
Advanced Javascript Unit Testing
 
Advanced QUnit - Front-End JavaScript Unit Testing
Advanced QUnit - Front-End JavaScript Unit TestingAdvanced QUnit - Front-End JavaScript Unit Testing
Advanced QUnit - Front-End JavaScript Unit Testing
 
Database Schema Evolution
Database Schema EvolutionDatabase Schema Evolution
Database Schema Evolution
 
Advanced Jasmine - Front-End JavaScript Unit Testing
Advanced Jasmine - Front-End JavaScript Unit TestingAdvanced Jasmine - Front-End JavaScript Unit Testing
Advanced Jasmine - Front-End JavaScript Unit Testing
 
Javascript unit testing with QUnit and Sinon
Javascript unit testing with QUnit and SinonJavascript unit testing with QUnit and Sinon
Javascript unit testing with QUnit and Sinon
 
Continuous Integration for front-end JavaScript
Continuous Integration for front-end JavaScriptContinuous Integration for front-end JavaScript
Continuous Integration for front-end JavaScript
 
Automated Performance Testing
Automated Performance TestingAutomated Performance Testing
Automated Performance Testing
 
Agile Contracts
Agile ContractsAgile Contracts
Agile Contracts
 
Elephant Carpaccio
Elephant CarpaccioElephant Carpaccio
Elephant Carpaccio
 
Automated Testing for Embedded Software in C or C++
Automated Testing for Embedded Software in C or C++Automated Testing for Embedded Software in C or C++
Automated Testing for Embedded Software in C or C++
 
Unit Testing in JavaScript with MVC and QUnit
Unit Testing in JavaScript with MVC and QUnitUnit Testing in JavaScript with MVC and QUnit
Unit Testing in JavaScript with MVC and QUnit
 
Introduction to Automated Testing
Introduction to Automated TestingIntroduction to Automated Testing
Introduction to Automated Testing
 

Recently uploaded

React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - InfographicHr365.us smith
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样umasea
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)jennyeacort
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Velvetech LLC
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 

Recently uploaded (20)

React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - Infographic
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 

Unit testing legacy code

  • 1. Unit testing legacy code Lars Thorup ZeaLake Software Consulting May, 2014
  • 2. Who is Lars Thorup? ● Software developer/architect ● JavaScript, C# ● Test Driven Development ● Continuous Integration ● Coach: Teaching TDD and continuous integration ● Founder of ZeaLake ● @larsthorup
  • 3. The problems with legacy code ● No tests ● The code probably works... ● Hard to refactor ● Will the code still work? ● Hard to extend ● Need to change the code... ● The code owns us :( ● Did our investment turn sour?
  • 4. How do tests bring us back in control? ● A refactoring improves the design without changing behavior ● Tests ensure that behavior is not accidentally changed ● Without tests, refactoring is scary ● and with no refactoring, the design decays over time ● With tests, we have the courage to refactor ● so we continually keep our design healthy
  • 5. What comes first: the test or the refactoring?
  • 6. How do we get to sustainable legacy code? ● Make it easy to add characterization tests ● Have good unit test coverage for important areas ● Don't worry about code you don't need to change ● Test-drive all new code ● Now we own the code :)
  • 7. Making legacy code sustainable ● Select an important area ● Driven by change requests ● Add characterization tests ● Make code testable ● Refactor the code ● Add unit tests ● Remove characterization tests ● Small steps
  • 8. Characterization tests ● Characterize current behavior ● Integration tests ● Either high level unit tests ● Or end-to-end tests ● Don't change existing code ● Faulty behavior = current behavior: don't change it! ● Make a note to fix later ● Test at a level that makes it easy ● The characterization tests are throw-aways ● Demo: ● Web service test: VoteMedia ● End-to-end browser test: entrylist.demo.test.js
  • 9. Make code testable ● Avoid large methods ● They require a ton of setup ● They require lots of scenarios to cover all variations ● Avoid outer scope dependencies ● They require you to test at a higher level ● Avoid external dependencies ● ... a ton of setup ● They slow you down
  • 10. Refactor the code ● Add interface ● Inject a mock instead of the real thing ● Easier setup ● Infinitely faster Notifier EmailSvc IEmailSvc EmailSvcStub NotifierTest ● Extract method ● Split up large methods ● To simplify unit testing single behaviors ● Demo: VoteWithVideo_Vimas ● Add parameter ● Pass in outer-scope dependencies ● The tests can pass in their own dummy values ● Demo: Entry.renderResponse
  • 11. Add unit tests ● Now that the code is testable... ● Write unit tests for you small methods ● Pass in dummy values for parameters ● Mock dependencies ● Rinse and repeat...
  • 12. Remove the characterization tests ● When unit test code coverage is good enough ● To speed up feedback ● To avoid test duplication
  • 13. Small steps - elephant carpaccio ● Any big refactoring... ● ...can be done in small steps ● Demo: Security system (see slide 19 through 31)
  • 14. Test-drive all new code ● Easy, now that unit testing tools are in place Failing test Succeeding test Good design Refactor Test Intention Think, talk Code
  • 15. Making legacy code sustainable ● Select an important area ● Driven by change requests ● Add characterization tests ● Make code testable ● Refactor the code ● Add unit tests ● Remove characterization tests ● Small steps
  • 16. It's not hard - now go do it! ● This is hard ● SQL query efficiency ● Cache invalidation ● Scalability ● Pixel perfect rendering ● Cross-browser compatibility ● Indexing strategies ● Security ● Real time media streaming ● 60fps gaming with HTML5 ● ... and robust Selenium tests! ● This is not hard ● Refactoring ● Unit testing ● Dependency injection ● Automated build and test ● Continuous Integration ● Fast feedback will make you more productive ● ... and more happy
  • 17. A big refactoring is needed...
  • 18. Avoid feature branches ● For features as well as large refactorings ● Delayed integration ● Increases risk ● Increases cost
  • 19. Use feature toggles ● Any big refactoring... ● ...can be done in small steps ● Allows us to keep development on trunk/master ● Drastically lowering the risk ● Commit after every step ● At most a couple of hours
  • 20. Security example ● Change the code from the old security system ● To our new extended security model interface IPrivilege { bool HasRole(Role); } class Permission { bool IsAdmin(); }
  • 21. Step 0: existing implementation ● Code instantiates Legacy.Permission ● and calls methods like permission.IsAdmin() ● ...all over the place ● We want to replace this with a new security system void SomeController() { var p = new Permission(); if (p.IsAdmin()) { ... } }
  • 22. Step 1: New security implementation ● Implements an interface ● This can be committed gradually interface IPrivilege { bool HasRole(Role); } class Privilege : IPrivilege { bool HasRole(Role r) { ... } }
  • 23. Step 2: Wrap the old implementation ● Create Security.LegacyPermission ● Implement new interface ● Wrap existing implementation ● Expose existing implementation class LegacyPermission : IPrivilege { LegacyPermission(Permission p) { this.p = p; } bool HasRole(Role r) { if (r == Role.Admin) return p.IsAdmin(); return false; } Permission Permission { get: { return p; } } private Permission p; }
  • 24. Step 3: Factory ● Create a factory ● Have it return the new implementation ● Unless directed to return the wrapped old one class PrivilegeFactory { IPrivilege Create(bool old=true) { if(!old) { return new Privilege(); } return new LegacyPermission(); } }
  • 25. Step 4: Test compatibility ● Write tests ● Run all tests against both implementations ● Iterate until the new implementation has a satisfactory level of backwards compatibility ● This can be committed gradually [TestCase(true)] [TestCase(false)] void HasRole(bool old) { // given var f = new PrivilegeFactory(); var p = f.Create(old); // when var b = p.HasRole(Role.Admin); // then Assert.That(b, Is.True); }
  • 26. Step 5: Dumb migration ● Replace all uses of the old implementation with the new wrapper ● Immediately use the exposed old implementation ● This can be committed gradually void SomeController() { var priv = f.Create(true) as LegacyPermission; var p = priv.Permission; if (p.IsAdmin()) { ... } }
  • 27. Step 6: Actual migration ● Rewrite code to use the new implementation instead of the exposed old implementation ● This can be committed gradually void SomeController() { var p = f.Create(true); if (p.HasRole(Role.Admin) { ... } }
  • 28. Step 7: Verify migration is code complete ● Delete the property exposing the old implementation ● Go back to previous step if the code does not compile ● Note: at this point the code is still using the old implementation everywhere! class LegacyPermission : IPrivilege { ... // Permission Permission // { // get: { return p; } // } private Permission p; }
  • 29. Step 8: Verify migration works ● Allow QA to explicitly switch to the new implementation ● We now have a Feature Toggle ● Do thorough exploratory testing with the new implementation ● If unintented behavior is found, go back to step 4 and add a new test that fails for this reason, fix the issue and repeat class PrivilegeFactory { IPrivilege Create(bool old=true) { var UseNew = %UseNew%; if(!old || UseNew) { return new Privilege(); } return new LegacyPermission(); } }
  • 30. Step 9: Complete migration ● Always use the new implementation ● Mark the old implementation as Obsolete to prevent new usages class PrivilegeFactory { IPrivilege Create() { return new Privilege(); } } [Obsolete] class Permission { ... }
  • 31. Step 10: Clean up ● After proper validation in production, delete the old implementation