Build Testable Client and Service Applications Brian Noyes IDesign Inc (www.idesign.net) brian.noyes@idesign.net About Brian Chief Architect IDesign Inc. (www.idesign.net) Microsoft Regional Director MVP Microsoft MVP Connected Systems Publishing Developing Applications with Windows Workflow Foundation, LiveLessons training DVD, June 2007 Smart Client Deployment with ClickOnce, Addison Wesley, January 2007 Data Binding in Windows Forms 2.0, Addison Wesley, January 2006 MSDN Magazine, MSDN Online, CoDe Magazine, The Server Side.NET, asp.netpro, Visual Studio Magazine Speaking E-mail: brian.noyes@idesign.net Blog: http://briannoyes.net Microsoft TechEd US, Europe, Malaysia, Visual Studio Connections, DevTeach, INETA Speakers Bureau, MSDN Webcasts 1
Agenda Design for Testability S.O.L.I.D. Principles IoC / Dependency Injection Separated Presentation Repository Pattern Testability Tricks Design for Testability Should this really be the way you think about it? A good design with high quality is the goal, not that you can test it Some changes to design and process are a necessity if you want to be testable Affects design at the component level, rarely at the system level May influence technology selections 2
TDD Should you use TDD? Probably Will it be hard to get used to? Probably Do I need to become a card-carrying zealot? No What does TDD buy you? Drives a clean design Ensures your app is testable Puts the tests in place as part of the process Mocks, Stubs, Fakes, oh my Terminology: Mock a test double that has expectations on how it is called Stub a test double that provides data to a test without breaking the test if its usage is different than the test specifies Fake has a real implementation, but simplified to just what the test needs Dummy object that provides a reference to unit under test, but is not called in general and does nothing Generalization: Mocks is often used to refer to all of these. Cleaner term is Test Double 3
Test Double Client Business Layer Component Data Layer Component Production Unit Test Business Layer Component Data Layer Double Test Agenda Design for Testability S.O.L.I.D. Principles IoC / Dependency Injection Separated Presentation Repository Pattern Testability Tricks 4
S.O.L.I.D. Principles Single Responsibility Principle (SRP) Open-Close Principle (OCP) Liskov Substitution Principle (LSP) Interface Segregation Principle (ISP) Dependency Inversion Principle (DIP) Documented by Robert (Uncle Bob) Martin of ObjectMentor http://butunclebob.com/articles.unclebob.principlesofood Single Responsibility Principle A class should have only one reason for change Ex: Order rich business object Contains data Implements business rules Does data persistence Should be at least 3 classes Simple, focused classes and methods are also much easier to test 5
Open-Close Principle You should be able to extend a class behavior without changing it Clients should depend on an abstraction of the actual object they are using Ex: Rendering engine IShape.Render() Open-Close Principle Extensions Basis for many modern best practices: Encapsulated member variables Aggressively avoid globals (static variables/props) Beware explicit casting Violating these practices is the enemy of testability 6
Liskov Substitution Principle Derived classes must be substitutable for their base classes Can also apply to component-based extensibility and plug-in architectures based on interfaces Drives Design by Contract mentality Ex: Rectangle/Square hierarchy What should happen if someone calls SetHeight on a Square vs a Rectangle? Dependency Inversion Principle Depend on abstractions, not concrete implementations Allow multiple concrete implementations to be substituted Basis for interface-based programming ESSENTIAL for testability Leads to dependency injection patterns 7
Interface Segregation Principle Make fine-grained interfaces that are client specific Separate contract per-usage scenario SRP extended to interface design Prevents needing to change a client if some functionality they don t use does not change Avoid potential for breakage Looser coupling facilitates testing Agenda Design for Testability S.O.L.I.D. Principles IoC / Dependency Injection Separated Presentation Repository Pattern Testability Tricks 8
Inversion of Control / Dependency Injection Closely related patterns IoC: Pattern for indirect construction of objects Delegate responsibility for construction of objects to a Container Dependency Injection Dependencies of an object are injected from the outside instead of constructing internally Most Containers do both Container constructs objects and injects their dependencies Dependencies are often located using Service Locator pattern.net DI Containers Unity MEF? Castle Windsor StructureMap Spring.NET NInject CAB WorkItem 9
DI Container Functions Object construction Injection of dependencies Child object relations Service Locator Lifetime management How long does the object live and what instance is given to the caller when they ask DI and Testability DI allows you to design a more loosely coupled application Generally need to adhere to S.O.L.I.D. Principles for it to work out Good pattern even if you don t unit test Extensibility, auto-wiring, centralized lifetime management Allows easy substitution of test doubles 10
DI and WCF WCF normally constructs service instances itself based on your selected instancing model Per Call, Per Session, Singleton To leverage a DI container in WCF, you have to intercept the construction process and let the DI container do it Service behavior Instance Provider Agenda Design for Testability S.O.L.I.D. Principles IoC / Dependency Injection Separated Presentation Repository Pattern Testability Tricks 11
Model View Controller (MVC) Model is the business logic and data View is a single page or chunk of screen Controller decides when to present each view / coordinates view-view interactions Model View Presenter 12
Presentation Model Also known as Model-View-ViewModel in the WPF / Silverlight world (MVVM) ViewModel offers up state to the view in the way the view wants to see it ViewModel Offers up state to the view through simple properties Encapsulates interaction logic to support the view Initial load of data Command handlers Should be loosely coupled to the view Relationship with the view 1:1 most common 1 view : multiple view models (example: Add/Edit ) Multiple views : 1 ViewModel (example: listing/details views) Properties should raise change events Implement INotifyPropertyChanged or DependencyProperties 13
Agenda Design for Testability S.O.L.I.D. Principles IoC / Dependency Injection Separated Presentation Repository Pattern Testability Tricks Repository Pattern Fowler: Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects. Interface separation between persistence strategy and application usage of data Allows you to change implementation Allows you to test with double implementation Simple collection oriented API (All, Where, Update,Delete,etc.) Can include other transmogrify methods (SimpleCustomerWhere) May have multiple entity types on a single repository interface Usually supporting types for a single parent concept (i.e. Customer/Address) 14
Repositories Using the repository pattern can help a lot in testing Isolate the specifics of persistence from the consuming objects Persistence is the most test-resistant part of your code Become a point for dependency injection for testing Allow you to switch to a different implementation strategy later with no impact on application i.e. LINQ to SQL -> Entity Framework Agenda Design for Testability S.O.L.I.D. Principles IoC / Dependency Injection Separated Presentation Repository Pattern Testability Tricks 15
Testability Tricks Avoid inline construction of dependencies Define dependencies as members if possible Define dependency injection constructors Even if you don t use a container Use for tests to inject test doubles Use overridable factory methods for dynamically created dependencies Can override in a test version of the class to inject test doubles Avoid static members / singletons Create Simulators and Emulators for your services Leverage a real isolation framework Rhino Mocks, MOQ, TypeMock Isolator, etc. G -word Guide http://misko.hevery.com/code-reviewersguide/ Smells: Constructor does real work Digging in to collaborators (dependencies) Law of Demeter Brittle Global State and Singletons Class does too much 16
Resources S.O.L.I.D. principles: http://butunclebob.com/articles.unclebob.principlesofood Repository http://codebetter.com/blogs/karlseguin/archive/2008/12/22/new-repository-lt-t-gt-domagic.aspx http://blog.wekeroad.com/mvc-storefront/asp-net-mvc-mvc-storefront-part-2/ Unity http://www.codeplex.com/unity Separated Presentation http://martinfowler.com/eaadev/separatedpresentation.html Using DI: http://www.codethinked.com/post/2009/03/23/to-inject-or-not-to-inject.aspx E-mail: brian.noyes@idesign.net Blog: http://briannoyes.net 17