Designing For Testability

Slides:



Advertisements
Similar presentations
Testing Object Oriented Programs CSE 111 4/28/20151.
Advertisements

Spring, Hibernate and Web Services 13 th September 2014.
Design Patterns Copyright © Vyacheslav Mukhortov, Nikita Nyanchuk-Tatarskiy, Copyright © INTEKS LLC,
Iterators T.J. Niglio Computer & Systems Engineering Fall 2003 Software Design & Documentation Object Behavioral.
Module: Definition ● A logical collection of related program entities ● Not necessarily a physical concept, e.g., file, function, class, package ● Often.
Interfaces. In this class, we will cover: What an interface is Why you would use an interface Creating an interface Using an interface Cloning an object.
Design Patterns academy.zariba.com 1. Lecture Content 1.What are Design Patterns? 2.Creational 3.Structural 4.Behavioral 5.Architectural 6.Design Patterns.
Unit Testing Tips and Tricks: Database Interaction Louis Thomas.
Who am I? ● Catalin Comanici ● QA for 10 years, doing test automation for about 6 years ● fun guy and rock star wannabe.
Creational Patterns Making Objects The Smart Way Brent Ramerth Abstract Factory, Builder.
Dependency Injection and Model-View-Controller. Overview Inversion of Control Model-View-Controller.
REFACTORING Lecture 4. Definition Refactoring is a process of changing the internal structure of the program, not affecting its external behavior and.
MVC and MVP. References enter.html enter.html
CISC6795: Spring Object-Oriented Programming: Polymorphism.
CSC 213 – Large Scale Programming. Why Do We Test?
Designing For Testability. Incorporate design features that facilitate testing Include features to: –Support test automation at all levels (unit, integration,
Todd Snyder Development Team Lead Infragistics Experience Design Group.
CSC 142 O 1 CSC 142 Java More About Inheritance & Interfaces [Reading: chapter 13]
Capture-Replay Mocks Scandinavian Developer Conference 4 th April 2011 Geoff Bache.
Spring core v3.x Prepared by: Nhan Le. History v3.0 Spring Expression Language Java based bean metadata v3.1 Cache Abstraction Bean Definition Profile.
Abstract Factory Design Pattern making abstract things.
@DNNCon Don’t forget to include #DNNCon in your tweets! Effective Unit Testing for DNN James McKee Solutions Developer / Enterprise
Test Isolation and Mocking Technion – Institute of Technology Author: Gal Lalouche © 1 Author: Gal Lalouche - Technion 2015 ©
Dependency Injection Technion – Institute of Technology Author: Gal Lalouche - Technion 2015 ©
The Factory Patterns SE-2811 Dr. Mark L. Hornick 1.
Design Patterns Gang Qian Department of Computer Science University of Central Oklahoma.
Refactoring for Testability (or how I learned to stop worrying and love failing tests) Presented by Aaron Evans.
Using Mock Objects with Test Driven Development Justin Kohlhepp
Unit 4 Object-Oriented Design Patterns NameStudent Number CAI XIANGHT082182A KYAW THU LINHT082238Y LI PENGFEIHT082220L NAUNG NAUNG LATTHT082195L PLATHOTTAM.
Alternative Architectures: Inversion of Control Mike Hadlow mikehadlow.blogspot.com.
Refactoring & Testability. Testing in OOP programming No life in flexible methodologies and for refactoring- infected developers without SOME kind of.
Interfaces About Interfaces Interfaces and abstract classes provide more structured way to separate interface from implementation
Design Patterns Software Engineering CS 561. Last Time Introduced design patterns Abstraction-Occurrence General Hierarchy Player-Role.
Dependency Injection Frameworks Technion – Institute of Technology Author: Assaf Israel - Technion 2013 ©
Mock Me If You Can An Introduction to the Mocking Framework Mockito Symposium on Software Performance 2014 Christian Wulf ― Software Engineering.
 An essential supporting structure of any thing  A Software Framework  Has layered structure ▪ What kind of functions and how they interrelate  Has.
Secrets of an Umbraco Ninja Presented by : Aaron powell.com.
Chapter 9: Coupling & Cohesion Omar Meqdadi SE 273 Lecture 9 Department of Computer Science and Software Engineering University of Wisconsin-Platteville.
Dependency Injection with Guice Technion – Institute of Technology Author: Gal Lalouche - Technion 2016 ©
Designing applications Main concepts to be covered Discovering classes CRC cards Designing interfaces Patterns © 2017 Pearson Education, Inc. Hoboken,
Test Isolation and Mocking Technion – Institute of Technology Author: Gal Lalouche © 1 Author: Gal Lalouche - Technion 2016 ©
Lessons Learned in Testability
Design Patterns Spring 2017.
Where are we ? Setup Sprites Input Collision Drawing Sprites
Chapter 10 Design Patterns.
GoF Patterns (GoF) popo.
MPCS – Advanced java Programming
Coupling and Cohesion 1.
Test Isolation and Mocking
Low Budget Productions, LLC
Designing For Testability
Week 2, Day 1: The Factory Method Pattern
Inheritance and Polymorphism
Input Space Partition Testing CS 4501 / 6501 Software Testing
Data Abstraction: The Walls
Chapter 8 – Software Testing
Unit Testing & Test-Driven Development for Mere Mortals
Design Patterns in Operating Systems
GoF Design Patterns (Ch. 26). GoF Design Patterns Adapter Factory Singleton Strategy Composite Façade Observer (Publish-Subscribe)
Unit Testing & Test-Driven Development for Mere Mortals
History, Characteristics and Frameworks
Mocking Your Objects with Impunity
Present by Andie Saizan, MCP
Model-View-Controller Patterns and Frameworks
Advanced Java Programming
Ms Munawar Khatoon IV Year I Sem Computer Science Engineering
More About Inheritance & Interfaces
Unit Testing & Test-Driven Development for Mere Mortals
GoF Design Patterns (Ch. 26)
Applying Use Cases (Chapters 25,26)
Presentation transcript:

Designing For Testability

Characteristics of Testable Code Highly cohesive Loosely coupled Dependencies minimized Dependency injected Minimal use of static methods and final methods Static methods contain few parameters Complex object creation logic is placed in Factories and/or Builders

Features that are Difficult to Automate Dependencies created by the class under test Prevents mocking / unit isolation Final methods Can’t be overridden by mocks or other types of test doubles Static methods Code that contains complex object creation logic (especially if it creates complex object graphs) GUI / View Code

Strategies Test-Driven Development Dependency Injection Use of configurable factories with simple (preferably no-argument) constructors In-class wrapper methods for calls to static method Use of MVC / MVP with view interfaces

Problem: Dependencies Created by the Class Under Test public class PayrollProcessor { private DatabaseService dbService; public PayrollProcessor() { dbService = new DatabaseService(); } public double getTaxAmount(String employeeID) { Employee emp = dbService.getEmployee(employeeID); double taxAmount = 0; // Some complicated code that uses information from // 'emp' to calculate taxes return taxAmount; } }

Solution Dependency Injection Mocking of the DatabaseService instance in the test public class PayrollProcessor2 { private DatabaseService dbService; public PayrollProcessor2(DatabaseService dbService) { this.dbService = dbService; } public double getTaxAmount(String employeeID) { Employee emp = dbService.getEmployee(employeeID); double taxAmount = 0; // Some complicated code that uses information from 'emp' to // calculate taxes return taxAmount; } }

Solution: Setter Injection public class PayrollProcessor3 { private DatabaseService dbService; public void setDbService(DatabaseService dbService) { this.dbService = dbService; } public double getTaxAmount(String employeeID) { Employee emp = dbService.getEmployee(employeeID); double taxAmount = 0; // Some complicated code that uses information from 'emp' to // calculate taxes return taxAmount; } }

The “Mock Object” design pattern Allows “mock objects” to be inserted anywhere in a program Allows a class to be isolated from its dependencies during unit testing, or for other reasons (e.g., a class I depend on doesn’t exist yet, or I want to avoid calling it for some reason) Supports “fault injection” Cause the software to fail at points where it normally wouldn’t to test error handling code Easy to generate with frameworks such as Mockito and EasyMock

The “Mock Object” design pattern Mock objects can simulate the behavior of complex, real (non-mock) objects and are therefore useful when a real object is impractical or impossible to incorporate into a unit test. If an object has any of the following characteristics, it may be useful to use a mock object in its place: supplies non-deterministic results (e.g., current time or current temperature); has states that are difficult to create or reproduce (e.g., a network error); is slow (e.g., a complete database, which would have to be initialized); does not yet exist or may change behavior; would have to include information and methods exclusively for testing purposes (and not for its actual task). Mock object method implementations can contain assertions of their own. This means that a true mock, in this sense, will examine the context of each call— perhaps checking the order in which its methods are called, perhaps performing tests on the data passed into the method calls as arguments.

Mock Object Creation with Mockito public class PayrollProcessorTest { @Test public void testGetTaxAmount() { DatabaseService mockDBService = Mockito.mock(DatabaseService.class); Employee mockEmployee = Mockito.mock(Employee.class); Mockito.doReturn(mockEmployee).when( mockDBService.getEmployee(Mockito.anyString())); // Mockito.when calls to setup mockEmployee to do what we will write // our test to expect PayrollProcessor2 processor = new PayrollProcessor2(mockDBService); // Code to test the getTaxAmount() method assuming that the // DatabaseService returns an employee object that does what we mocked // our mockEmployee to do } }

Dependency Injection Programming style that allows objects to receive their dependencies instead of creating them Makes your design more flexible (dependencies are no longer “hard-coded” into the class that uses them Facilitates testing by making it easy for a test to mock a dependency Choose a “Dependency Injection Container” Spring, Ninject, Google Guice, etc. Configure your dependency injection container with a mapping from abstract interfaces to concrete classes that implement them Create objects by asking the dependency injection container for an implementation of an abstract interface Allows program code to depend on abstract interfaces, and not on concrete classes Allows mock objects to be easily inserted anywhere in the code

Problem: Final Methods Mocking frameworks mock interfaces by creating their own implementations They mock classes by creating subclasses Final methods cannot be sub-classed, so most mocking frameworks cannot mock them Final methods can be tested, but if the dependency you want to mock has a final method, you typically cannot replace that method with a mock implementation Can’t do this: Mockito.doReturn(xyz).when(mockObject.myFinalMethod())

Solutions Minimize the use of final methods (warning: virtual methods are slower than final methods) Use a mocking framework that can mock final methods (i.e. PowerMock) PowerMock is slow Generally considered bad practice to use it

Problem: Static Methods Similar problems as final methods Can’t be mocked by most mocking frameworks Static methods are testable, but classes that have dependencies on them are difficult to test

Solutions Minimize the use of static methods Wrap calls to static methods in non-static methods in the dependent class Use a mocking framework that can mock static methods (i.e. PowerMock)

Problem: Code that Contains Complex Creation Logic Similar to the general problem of classes that create their own dependencies Difficult to use dependency injection

Solution Use a factory to create the dependency object(s) Use a non-static ‘get…’ method to create the object Makes the entire factory mockable public class ServiceFactory { public DatabaseService getDatabaseService() { DatabaseService dbService = null; // Complex logic to create and initialize a // database service instance. return dbService; } }

Factory in Greater Detail

Problem: GUI / View Code GUIs are difficult to test using test automation tools GUIs change frequently (making GUI test code brittle) GUI automation tools (i.e. Selenium for browser-based applications) are somewhat flaky GUI tests that automate and mimic user behavior are slow (due to screen creation and redraws)

Solution Use an MVC / MVP design Separate actual view code from what can go in controller/presenter and model classes that are easier to test Use interfaces for your views and make controllers/presenters only depend on the view interfaces (not the actual views) Allows mocking of the view code Will still need a few system level tests (automated or manual) but most view code can be tested without actually generating the view