SlideShare una empresa de Scribd logo
1 de 31
Descargar para leer sin conexión
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

Más contenido relacionado

La actualidad más candente

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
 

La actualidad más candente (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 a 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 a 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
 

Más de 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
 

Más de 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
 

Último

SoftTeco - Software Development Company Profile
SoftTeco - Software Development Company ProfileSoftTeco - Software Development Company Profile
SoftTeco - Software Development Company Profileakrivarotava
 
Not a Kubernetes fan? The state of PaaS in 2024
Not a Kubernetes fan? The state of PaaS in 2024Not a Kubernetes fan? The state of PaaS in 2024
Not a Kubernetes fan? The state of PaaS in 2024Anthony Dahanne
 
Osi security architecture in network.pptx
Osi security architecture in network.pptxOsi security architecture in network.pptx
Osi security architecture in network.pptxVinzoCenzo
 
Amazon Bedrock in Action - presentation of the Bedrock's capabilities
Amazon Bedrock in Action - presentation of the Bedrock's capabilitiesAmazon Bedrock in Action - presentation of the Bedrock's capabilities
Amazon Bedrock in Action - presentation of the Bedrock's capabilitiesKrzysztofKkol1
 
Leveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
Leveraging AI for Mobile App Testing on Real Devices | Applitools + KobitonLeveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
Leveraging AI for Mobile App Testing on Real Devices | Applitools + KobitonApplitools
 
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxUI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxAndreas Kunz
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsSafe Software
 
Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Rob Geurden
 
Ronisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited CatalogueRonisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited Catalogueitservices996
 
What’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesWhat’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesVictoriaMetrics
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtimeandrehoraa
 
Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...
Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...
Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...OnePlan Solutions
 
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Cizo Technology Services
 
Sending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdfSending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdf31events.com
 
2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shards2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shardsChristopher Curtin
 
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingOpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingShane Coughlan
 
VK Business Profile - provides IT solutions and Web Development
VK Business Profile - provides IT solutions and Web DevelopmentVK Business Profile - provides IT solutions and Web Development
VK Business Profile - provides IT solutions and Web Developmentvyaparkranti
 
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptx
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptxReal-time Tracking and Monitoring with Cargo Cloud Solutions.pptx
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptxRTS corp
 
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...confluent
 
Patterns for automating API delivery. API conference
Patterns for automating API delivery. API conferencePatterns for automating API delivery. API conference
Patterns for automating API delivery. API conferencessuser9e7c64
 

Último (20)

SoftTeco - Software Development Company Profile
SoftTeco - Software Development Company ProfileSoftTeco - Software Development Company Profile
SoftTeco - Software Development Company Profile
 
Not a Kubernetes fan? The state of PaaS in 2024
Not a Kubernetes fan? The state of PaaS in 2024Not a Kubernetes fan? The state of PaaS in 2024
Not a Kubernetes fan? The state of PaaS in 2024
 
Osi security architecture in network.pptx
Osi security architecture in network.pptxOsi security architecture in network.pptx
Osi security architecture in network.pptx
 
Amazon Bedrock in Action - presentation of the Bedrock's capabilities
Amazon Bedrock in Action - presentation of the Bedrock's capabilitiesAmazon Bedrock in Action - presentation of the Bedrock's capabilities
Amazon Bedrock in Action - presentation of the Bedrock's capabilities
 
Leveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
Leveraging AI for Mobile App Testing on Real Devices | Applitools + KobitonLeveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
Leveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
 
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxUI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data Streams
 
Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...
 
Ronisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited CatalogueRonisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited Catalogue
 
What’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesWhat’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 Updates
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtime
 
Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...
Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...
Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...
 
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
 
Sending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdfSending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdf
 
2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shards2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shards
 
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingOpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
 
VK Business Profile - provides IT solutions and Web Development
VK Business Profile - provides IT solutions and Web DevelopmentVK Business Profile - provides IT solutions and Web Development
VK Business Profile - provides IT solutions and Web Development
 
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptx
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptxReal-time Tracking and Monitoring with Cargo Cloud Solutions.pptx
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptx
 
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
 
Patterns for automating API delivery. API conference
Patterns for automating API delivery. API conferencePatterns for automating API delivery. API conference
Patterns for automating API delivery. API conference
 

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