When working with legacy code, subsequent covering with unit tests is not an easy task. Quite often one is faced with the dilemma of refactoring - you need tests for safely refactorings, but the code needs to be refactored first in order to write any tests.
Bringing existing code in better shape is essential when existing code must be covered with unit tests. In this presentation we focus on refactorings that are targeted for covering legacy code with unit tests, after it has been written without tesing in mind.
These are the slides of the presentation. See also:
- Handout: http://www.slideshare.net/rfilipov/refactoring-fortests-handout
- Sources: https://github.com/rusio/refactoring-for-tests
- Update: http://www.slideshare.net/rfilipov/refactoring-fortestability
1. Refactoring for Tests
Rusi Filipov
●
Software Engineer at
Lindenbaum GmbH
●
At Work: Maintain a
Conferencing System
●
Interests: CCD, OOD,
TDD
Rusi Filipov Clean Code Days 2013
2. Agenda for Today
●
General Idea
●
Object Design
●
Unit Testing
●
Code Samples
Rusi Filipov Clean Code Days 2013
5. Coupling: Static Dependencies
Object Peer Stereotype: Collaborator
●
Object with Logic and Behaviour that We Use
●
In Test: Replace Collaborators with Mocks
●
Inject Mocked Collaborators in Object
● Code!
Rusi Filipov Clean Code Days 2013
6. Refactor: Static Dependencies
Pass Collaborators „from Above“
●
Don't Create Collaborators with „new“
●
Accept Collaborators via the Constructor
●
Who Should Create the Collaborators?
●
Parent Object, Main Module, Injector
●
What About Indirect Collaborators? Code!
Rusi Filipov Clean Code Days 2013
7. Coupling: Dynamic Dependencies
Situation: Not Possible to Create Collaborator
at Construction Time during Object Wiring
●
Not Enough Information about Collaborator
●
Information Available when Object is Active
●
Must Create Collaborator after Wiring
●
And Still Replace it with Mock Object in Test
● Code!
Rusi Filipov Clean Code Days 2013
8. Distraction: Doing Too Much
Situation: A Class is Overloaded With Many
Responsibilities That Prevent Good Testing
●
Class is not Focused to do One Thing
●
Instead: Eierlegende Wollmilchsau
=> Harder to Understand
=> Higher Bug Probability
=> Too Many Combinations to Test!
Rusi Filipov Clean Code Days 2013
9. Refactoring Challenge: FtpClient
Evolution of a „Feature-Rich“ FTP Client
●
List and Download Remote Files
●
Verify Checksum of Downloads
●
Cache Results from Listing
●
Reconnect if Connection Fails
●
Diagram, Code!
Rusi Filipov Clean Code Days 2013
12. Consequences for Structure
● More Units: +Interfaces, +Classes, +Factories
● Object Wiring Becomes More Important
● Injection, Parametrization „From Above“
● Gain: Lower Coupling, Higher Cohesion
=> Better Dependency Structure
=> Better Testability
Consequences for Structure
13. Consequences for Complexity
● Complexity Rises Because of More Units
● Complexity Falls Because Units are Simpler
● Negative: More Information Overload
– Use Package-Private (Java), internal (C#)
● Positive: Focused Units, Improved Coupling
● Better Understanding for Human
Consequences for Complexity
14. Final Thoughts
● Don't Write Bad Unit Tests if Testability is Low
● Refactor for Unit-Testing Instead!
● But Be Aware of the Risk
● Single Responsibility Principle
● Dependency Inversion Principle
● Avoid „Power“-Mocking, Partial-Mocks and Test-Spies
● Add Integration Tests ASAP
Rusi Filipov Clean Code Days 2013