Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016
-
Upload
steven-smith -
Category
Software
-
view
705 -
download
1
Transcript of Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016
![Page 1: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/1.jpg)
Breaking Dependencies
to Allow Unit TestingSteve Smith
Ardalis Services@ardalis | ardalis.com
![Page 2: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/2.jpg)
Tweet Away
• Live Tweeting and Photos are encouraged• Questions and Feedback are welcome• Use #DevIntersection and/or #breakDependencies• Or #DevIntersectionBreakingDependenciesToAllowUnitTesting (55
chars with space)
![Page 3: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/3.jpg)
Pluralsight
I have some 1-month free passes; see me after if you’d like one
![Page 4: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/4.jpg)
Questions up Front
What kinds of dependencies in your code cause you the most pain today?
![Page 5: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/5.jpg)
Legacy Code
“To me, legacy code is simply code without tests.”
Michael FeathersWorking Effectively with Legacy Code
![Page 6: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/6.jpg)
Unit Testing (Legacy) Code is…
![Page 7: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/7.jpg)
Here’s (Mostly) Why…
![Page 8: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/8.jpg)
Hollywood made a whole movie about it…
![Page 9: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/9.jpg)
But let’s back up…
• Why Unit Tests?• Why not just use other kinds of tests?• What are dependencies?
• How do we break these dependencies?
![Page 10: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/10.jpg)
Unit Tests Prevent Small Thermal Exhaust Ports in Your Code
![Page 11: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/11.jpg)
Unit Test Characteristics
• Test a single unit of code• A method, or at most, a class
• Do not test Infrastructure concerns• Database, filesystem, etc.
• Do not test “through” the UI• Just code testing code; no screen readers, etc.
![Page 12: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/12.jpg)
Unit Tests are (should be) FAST
• No dependencies means1000s of tests per second
• Run them constantly
![Page 13: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/13.jpg)
Unit Tests are SMALL
• Testing one thing should be simple• If not, can it be made simpler?
• Should be quick to write
![Page 14: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/14.jpg)
Unit Test Naming
• Descriptive And Meaningful Phrases (DAMP)• Name Test Class: ClassNameMethodName• Name Test Method: DoesSomethingGivenSomething• http://ardalis.com/unit-test-naming-convention
![Page 15: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/15.jpg)
Seams
• Represent areas of code where pieces can be decoupled• Testable code has many seams; legacy code has few, if any
![Page 16: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/16.jpg)
Kinds of TestsUI
Integration Tests
Unit Testshttp://martinfowler.com/bliki/TestPyramid.html
![Page 17: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/17.jpg)
Ask yourself:
•Can I test this scenario with a Unit Test?•Can I test it with an Integration
Test?• Can I test it with an automated UI Test?
UI
Integration Tests
Unit Tests
![Page 18: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/18.jpg)
Don’t believe your test runner…
Integration Test
![Page 19: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/19.jpg)
Unit Test?
• Requires a database or file?• Sends emails?• Must be executed through the
UI?
Not a unit test
![Page 20: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/20.jpg)
Dependencies and Coupling
All dependencies point toward infrastructure
Presentation Layer
Business Layer
InfrastructureData Access
Tests
Tests (and everything else) now depend on Infrastructure
![Page 21: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/21.jpg)
Dependency Inversion Principle
High-level modules should not depend on low-level modules. Both should depend on abstractions.
Abstractions should not depend on details. Details should depend on abstractions.
Agile Principles, Patterns, and Practices in C#
![Page 22: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/22.jpg)
Depend on Abstractions
All dependencies point toward Business Logic / CorePresentation
Layer
Business Layer
InfrastructureData Access
Unit Tests
Integration TestsUI Tests
![Page 23: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/23.jpg)
Inject Dependencies
• Classes should follow Explicit Dependencies Principle• http://deviq.com/explicit-dependencies-principle
• Prefer Constructor Injection• Classes cannot be created in an invalid state
https://flic.kr/p/5QsGnB
![Page 24: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/24.jpg)
Common Dependencies to Decouple
•Database•File System•Email•Web APIs
•System Clock•Configuration•Thread.Sleep•Random
![Page 25: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/25.jpg)
Tight Couplers: Statics and new
• Avoid static cling• Calling static methods with side effects
• Remember: new is glue• Avoid gluing your code to a specific implementation• Simple types and value objects usually OK
http://ardalis.com/new-is-glue
![Page 26: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/26.jpg)
Coupling Code Smells
• Learn more in my Refactoring Fundamentals course on Pluralsight• http://www.pluralsight.com/courses/refactoring-fundamentals
• Coupling Smells introduce tight coupling between parts of a system
![Page 27: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/27.jpg)
Feature Envy
• Characterized by many getter calls• Violates the “Tell, Don’t Ask” principle
• Instead, try to package data and behavior together• Keep together things that change together• Common Closure Principle – Classes that change together are
packaged together
![Page 28: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/28.jpg)
![Page 29: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/29.jpg)
![Page 30: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/30.jpg)
Law of Demeter
• Or the “Strongly Worded Suggestion of Demeter”• A Method m on an object O should only call methods on• O itself• m’s parameters• Objects created within m• O’s direct fields and properties• Global variables and static methods
![Page 31: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/31.jpg)
Law of Demeter
![Page 32: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/32.jpg)
Law of Demeter
![Page 33: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/33.jpg)
Law of Demeter
![Page 35: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/35.jpg)
Constructors
![Page 36: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/36.jpg)
Explicit Dependencies Principle
• Methods and classes should require their collaborators as parameters• Objects should never exist in an invalid state
http://deviq.com/explicit-dependencies-principle/
![Page 37: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/37.jpg)
Constructor Smells• new keyword (or static calls) in constructor or field
declaration• Anything more than field assignment!• Database access in constructor• Complex object graph construction• Conditionals or Loops
![Page 38: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/38.jpg)
Good Constructors
• Do not create collaborators, but instead accept them as parameters
• Use a Factory for complex object graph creation
• Avoid instantiating fields at declaration
![Page 39: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/39.jpg)
“”
IoC Containers are just factories on steroids.
Don’t be afraid to use them where they can help
![Page 40: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/40.jpg)
![Page 41: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/41.jpg)
![Page 42: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/42.jpg)
![Page 43: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/43.jpg)
![Page 44: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/44.jpg)
Avoid Initialize Methods
• Moving code out of the constructor and into Init()• If called from constructor, no different• If called later, leaves object in invalid state until called
• Object has too many responsibilities• If Initialize depends on infrastructure, object will still be hard to
test
![Page 45: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/45.jpg)
![Page 46: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/46.jpg)
![Page 47: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/47.jpg)
“Test” Constructors
• “It’s OK, I’ll provide an “extra” constructor my tests can use!”
• Great! As long as we don’t have to test any other classes that use the other constructor.
![Page 48: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/48.jpg)
![Page 49: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/49.jpg)
Avoid Digging into Collaborators
• Pass in the specific object(s) you need• Avoid using “Context” or “Manager” objects to access
additional dependencies• Violates Law of Demeter: Context.SomeItem.Foo()
• Suspicious Names: environment, principal, container • Symptoms: Tests have mocks that return mocks
![Page 50: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/50.jpg)
![Page 51: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/51.jpg)
![Page 52: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/52.jpg)
Avoid Global State Access
• Singletons• Static fields or methods• Static initializers• Registries• Service Locators
![Page 53: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/53.jpg)
Singletons
• Avoid classes that implement their own lifetime tracking• GoF Singleton Pattern
• It’s OK to have a container manage object lifetime and enforce having only a single instance of a class within your application
![Page 54: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/54.jpg)
![Page 55: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/55.jpg)
![Page 56: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/56.jpg)
Breaking Dependencies in Web Forms
Demo
![Page 57: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/57.jpg)
Answer QuestionsDemo
![Page 58: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/58.jpg)
Summary• Inject Dependencies• Remember “New is glue”.
• Keep your APIs honest• Remember the Explicit Dependencies Principle. Tell your friends.
• Maintain seams and keep coupling loose
![Page 59: Breaking Dependencies to Allow Unit Testing - DevIntersection Spring 2016](https://reader036.fdocuments.us/reader036/viewer/2022062822/587ac5861a28abc0478b7c87/html5/thumbnails/59.jpg)
Thanks!• Questions?
• Follow me at @ardalis
• Check out http://DevIQ.com for more on these topics• Take Pride in Your Code!
• References• http://misko.hevery.com/code-reviewers-guide/ • Working Effectively with Legacy Code
by Michael Feathers
Please use Event Board to fill out a session evaluation.