100 % confident with legacy code
DESCRIPTION
I T.A.K.E 2014 unconferenceTRANSCRIPT
100% Confident with Legacy
Code
Johan MARTINSSON
Developer - Independent
@johan_alps
Rémy SANLAVILLE
Developer - Orange Software Expert
@sanlaville
Working with Legacy Code
Working with Legacy Code
Refactoring Legacy Code with Object
Calisthenics2012 - 2013
Anonymous Developers - Season 1
Working with Legacy Code
100% Confident with Legacy Code
2014
Anonymous Developers - Season 2
Testing Legacy Code - Blockers
Integration tests are too long
Unit tests are too coupled to the source code
Hard and long to write tests
Testing Legacy Code
100% Confident with Legacy Code
2014
Anonymous Developers - Season 2
Testing Legacy Code
100% Confident with Legacy Code
2014
Anonymous Developers - Season 2
Testing Legacy Code
Don’t forget to replace
temporary refactoring
tests
by maintainable tests
Trivia Challengehttp://www.hasbro.com/games/en_US/shop/details.cfm?R=93C6EE71-
6D40-1014-8BF0-9EFBF894F9D4:en_US
https://github.com/jbrains/trivia
It simulates a trivia game
using a randomizer
for correct and wrong answers
How long do you need to
reach ~100% code coverage ?
Trivia Challengehttps://github.com/jbrains/trivia
http://www.hasbro.com/games/en_US/shop/details.cfm?R=93C6EE71-
6D40-1014-8BF0-9EFBF894F9D4:en_US
It works well because there
are no dependencies
1
1
Serialize game state and
compare it with Approval Tests1
Cover all branches by
variying the results of the
randomizer
2
2
Server 1Server 2
EncodeAudioLegacy Challenge
Remote Server 1
Audio File encoding
HTTPS Server 2
Audio File Encoded
Audio File
Audio File available
at Remote Server 1
Encoded Audio File
available
download upload
Encode Audio Engine
Baby Steps
Step0: Development environment validation
Step1: String comparison with ApprovalTests
Step2: Branch coverage by input parameter variation
Step3: Serializing a complex type
Step4: Mocking web services
Step5: Capturing side effects
Step 0: Development environment validation
EclEmmaJUnit
Technical Solution: Unit Testing + Code Coverage Tool + Diff
Tool
Context: Launch UT + Code Coverage + String comparison
Server 1
Remote Server 1
Audio Filedownload
Server 2
encoding
HTTPS Server 2
Audio File available
at Remote Server 1
Encode Audio Engineupload
Audio File Encoded
Audio File
Encoded
Audio File
Encoded Audio File
available
Meld
WinMerge…
Step 1: Method returns a primitive type
Technical Solution: Approval Tests (string comparison)
Context: No side effect + Method returns a primitive type
Server 1
Remote Server 1
Audio Filedownload
Server 2
encoding
HTTPS Server 2
Audio File available
at Remote Server 1
Encode Audio Engineupload
Audio File Encoded
Audio File
Encoded
Audio File
Encoded Audio File
available
Note: encoding issues
Step 2: Branches coverage by input
parameters variation
Technical Solution: Approval Tests (legacyApprovals)
Context: No side effect + Method returns a primitive type
Server 2
encoding
HTTPS Server 2
Audio File available
at Remote Server 1
Encode Audio Engineupload
Audio File Encoded
Audio File
Encoded
Audio File
Encoded Audio File
available
Server 1
Remote Server 1
Audio Filedownload
Step 3: Method returns a complex type
Note: date issues
Context: No side effect + Method returns a complex type
Technical Solution: Approval Tests + XStream
Server 1
Remote Server 1
Audio Filedownload
Server 2
encoding
HTTPS Server 2
Audio File available
at Remote Server 1
Encode Audio Engineupload
Audio File Encoded
Audio File
Encoded
Audio File
Encoded Audio File
available
IFluxTmlg
IBodyTmlg
ITravelInfoTmlg
IAudioAnnounceTmlg
Server 2
encoding
HTTPS Server 2
Audio File available
at Remote Server 1
Encode Audio Engineupload
Audio File Encoded
Audio File
Encoded
Audio File
Encoded Audio File
available
Step 4: Third-party services
Context: WebService difficult to configure or/and not
avalaible
Technical Solution: Moco
Server 1
Remote Server 1
Audio Filedownload
Step 5: Capturing side effects
Note: can be used for context with void methods
not mocking side effect
Context: Side effects
Technical Solution: State, Side Effects Serialization + Approval
Tests
Server 1
Remote Server 1
Audio Filedownload
Server 2
encoding
HTTPS Server 2
Audio File available
at Remote Server 1
Encode Audio Engineupload
Audio File Encoded
Audio File
Encoded
Audio File
Encoded Audio File
available
Conclusion - Why it’s working?
Easy assertion: record and replay
Even ugly tests do the job (Temporary tests)
Fast to execute
Available good libraries:
Approval Tests, XStream, Moco…
Tests are resilient to refactoring
Next…
http://approvaltests.sourceforge.net/
http://martinsson-johan.blogspot.fr/
http://github.com/dreamhead/moco
https://github.com/pearlfish/pearlfish-java
UI visual diffing
https://www.youtube.com/watch?v=UMnZiTL0tUc
Working Effectively with Legacy Code – in particular for
creating “seams”
http://approvaltests.sourceforge.net/
http://approvaltests.sourceforge.net/
Approval Tests
only needs 2
lines!
http://approvaltests.sourceforge.net/
Run your test
Diff Tool (by default TortoiseMerge)
Cf. Using Reporters in Approval Tests
http://blog.approvaltests.com/2011/12/using-reporters-in-approval-tests.html
http://approvaltests.sourceforge.net/
Result of the current test
named received
http://approvaltests.sourceforge.net/
Result reference
named approved
http://approvaltests.sourceforge.net/
Approve result
and save file
http://approvaltests.sourceforge.net/
BACKUP
Server 1Server 2
EncodeAudioLegacy Challenge
Remote Server 1
Audio File encoding
HTTPS Server 2
Audio File available
at Remote Server 1
download
Encode Audio Engineupload
AudioAnnouceTmlg
URL Remote Server 1
format
filename
audioConfigTmp
target audio file extension
target encoding properties
httpConfigTmp
Local Tempory Folder path,
URL Remote HTTPS Server 2
Local Tempory Folder
Audio File Encoded
Audio File
Local HTTP
Server
Encoded
Audio File
Encoded Audio File
availableAudioFile
name
format