6. GARY PEDRETTI
• Over 15 years in the software industry with highly cross-functional
experience – DBA, Developer, BA, Application Architect
• Currently Trainer, Coach, Consultant, Owner at Sodoto Solutions
• SODOTO = See One, Do One, Teach One
• Scrum: Development Team member, Scrum Master, Coach,
Professional Scrum Trainer for Scrum.org
• http://blog.GaryPedretti.com/
• http://www.linkedin.com/in/garypedretti
• Twitter: @GaryPedretti
• MCSD:ALM 2012
8. PROPORTIONS
To achieve these
proportions and still
cover the application
adequately requires
good application
architecture and design
patterns! “Quality is
built-in from the
beginning.”
UI
1% -
5%
Integration &
Service
5% - 15%
Unit
80% - 94%
9. TOOLS
UI
Selenium,
Coded UI,
QTP
Integration &
Service
Fit, Fitnesse, Unit Testing
Frameworks (where the
test is not isolated,
resulting in an Integration
or Service test)
Unit
MSTest, nUnit, mbUnit, xUnit,
jUnit, DB unit tests, qUnit, Moq,
RhinoMocks, Mockito
BDD frameworks
(Cucumber,SpecFlow)
could use any of these
test types and tools to
implement their test
steps
11. Unit Test
Business Logic
Mocked Data
Access Layer
Unit Test
Mocked
Database
Data Access
Layer
Testing
Pyramid
Real unit tests that
isolate dependencies
with fakes, mocks, stubs,
dummies, etc.
16. ON SOLID…
S
Single Responsibility
Principle
A class has one single responsibility and therefore
one reason to change.
O Open/Closed Principle Open for extensions, closed for modifications.
L Liskov Substitution Principle Subtypes must be substitutable for their base type.
I
Interface Segregation
Principle
Not one big interface for all clients, but one
interface per kind of client. No methods in interface
that client does not use. No “fat” interfaces.
D
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.
21. INVERSION OF CONTROL
See Fowler’s “Inversion of Control Containers and the
Dependency Injection pattern” at
http://martinfowler.com/articles/injection.html for a great
discussion on choices and tradeoffs here
Image from http://msdn.microsoft.com/en-us/library/ff921087.aspx
22. INVERSION OF CONTROL
Using MyApp.DataAccessLayer;
namespace MyApp.ServiceLayer
{
public class CoolService
{
public CoolThing GetCoolThing(int id)
{
CoolSQLRepository repository =
new CoolSQLRepository();
return repository.GetThing(id);
}
}
}
namespace MyApp.ServiceLayer
{
public class CoolService
{
private IRepository _MyRepository;
public CoolService(IRepository repository)
{
_MyRepository = repository;
}
public CoolThing GetCoolThing(int id)
{
return _MyRepository.GetThing(id);
}
}
public interface IRepository
{
CoolThing GetThing(int id);
}
}
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.
25. INVERSION OF CONTROL
SOLID Principles
• Single Responsibility Principle
• Dependency Inversion
Various -ilities, especially maintainability
Implementation Flexibility
Testability!!! Real Unit Tests at the Bottom of Your Pyramid!!
29. ASPECT-ORIENTED
PROGRAMMING
public class MegaDivider
{
private ILog logger;
public int Divide(int numerator, int denominator)
{
logger.DebugFormat("MegaDivider.Divide method entered at ", DateTime.UtcNow);
try
{
return numerator / denominator;
}
finally
{
logger.DebugFormat("MegaDivider.Divide method left at ", DateTime.UtcNow);
}
33. ASPECT-ORIENTED
PROGRAMMING
SOLID Principles
• Single Responsibility Principle
Various -ilities, especially maintainability
Domain Driven Design (DDD) ideas (a/k/a “Real” Object-
Orientation)
• Readability
Testability!!! Real Unit Tests at the Bottom of Your Pyramid!!
38. MV* PATTERNS
SOLID Principles…various -ilities, especially maintainability
• Single Responsibility Principle
In-Line With Various Modern Frameworks and Tools
Testability!!! For the Pyramid:
• Model: Unit Testable
• Controllers/Presenters/View Models: Unit Testable
• View: Very Thin (IF YOU FOLLOW THE INTENDED
PRINCIPLES), Allows You To Keep the Top of Your Pyramid
Small
40. TESTING PYRAMID =
GOOD DESIGN
Now you have good ideas about the WHYs of
• Inversion of Control (IoC)
• Aspect-Oriented Programming (AOP)
• MVx (MVC, MVP, MVVM)
41. TESTING PYRAMID =
GOOD DESIGN
• The WHYs for All 3 of These Are In Direct Support of the
Testing Pyramid
• The WHYs for All 3 of These Are In Direct Support of Good
Application Architecture and Design
42. TESTING PYRAMID =
GOOD DESIGN
• The Testing Pyramid = Good Application Architecture and
Design
• The Testing Pyramid != Testing ??
• The Testing Pyramid = Application Architecture and
Design Statement !!
There's a pyramid in Giza, Egypt. It's been there for about 4,500 years now. It's the oldest of the original 7 wonders of the world, and the ONLY one still standing. It was the tallest man made structure in the world for over 3,800 years. It is the epitome of architectural integrity and longevity - it's lasted for so long because of the very nature of a pyramid - low center of gravity, things are only added to a base which is more solid than what you're adding, etc.
There's another pyramid, from Mike Cohn, introduced in his 2009 book Succeeding With Agile. It's the Test Automation Pyramid, and it explains a suggested approach to test automation that maximizes Return on Investment, by encouraging the concentration of your testing efforts primarily in the Unit testing area, with some effort in Service layer/integration tests, and the minimal effort in the fragile area of UI testing. Although it's ostensibly about test automation, I would like to propose that Cohn's pyramid has more value as an architectural or design statement, much like the Great Pyramid of Giza, and it can lend the same sort of integrity and longevity to our applications that is exhibited by the Great Pyramid. As the *Test Automation* Pyramid it has great value, but we're leaving all kinds of value on the table by viewing it as only that. In fact, we need to think about it as an architecture and design statement early and continuously, or we won't even be able to use it for Test Automation.
What do I mean? In order to get full coverage of an application from tests broken out in the ratios described by the Test Automation Pyramid, we must have an app that is continuously designed and refactored a certain way. It doesn't happen by accident.
“Quality is built-in from the beginning” “Quality is job #1” and 42,000 other clichés…
I'd like to talk about 3 patterns or orientations that allow us to design for the Testing Pyramid. They have all been very popular patterns for some time now, but I'd like to go beyond the buzzword trafficking and just doing "what the cool kids do" to explain the "whys" behind using these patterns. The patterns I'd like to talk about are Inversion of Control, Aspect Oriented Programming, and Model View Controller.
The typical layered application looks like this
In the past we'd have hard dependencies flowing downwards. IoC via Dependency Injection or the Service Locator pattern, together with a mocking framework, allows us to isolate each individual layer to be completely unit testable.
The typical layered application looks like this
In the past we'd have hard dependencies flowing downwards. IoC via Dependency Injection or the Service Locator pattern, together with a mocking framework, allows us to isolate each individual layer to be completely unit testable.
Inversion of Control is a concept. There are at least two patterns you can use to achieve Inversion of Control: Dependency Injection (constructor or property) or the sometimes-forgotten Service Locator.
In the past we'd also have a silo for cross-cutting concerns. This often included components for things needed by any layer, such as logging. But the application layers took hard dependencies on this silo to the side, not just from component references but even worse, through ugly, repetitive, boilerplate code riddled throughout every method of every class of every component.
AOP allows us to isolate the silo, and only plug it in dynamically at runtime, such as before and after the execution of an object's methods. This makes something like the logging component completely testable in isolation, but more importantly, leaves the application layers much cleaner, allowing for real unit tests, not there, not integration tests.
From :
Aspect: A modularization of a concern that cuts across multiple objects. Transaction management is a good example of a crosscutting concern in J2EE applications. In Spring AOP, aspects are implemented using regular classes (the schema-based approach) or regular classes annotated with the @Aspect annotation (@AspectJ style).
Join point: A point during the execution of a program, such as the execution of a method or the handling of an exception. In Spring AOP, a join point always represents a method execution. Join point information is available in advice bodies by declaring a parameter of type org.aspectj.lang.JoinPoint.
Advice: Action taken by an aspect at a particular join point. Different types of advice include "around," "before" and "after" advice. Advice types are discussed below. Many AOP frameworks, including Spring, model an advice as an interceptor, maintaining a chain of interceptors "around" the join point.
Pointcut: A predicate that matches join points. Advice is associated with a pointcut expression and runs at any join point matched by the pointcut (for example, the execution of a method with a certain name). The concept of join points as matched by pointcut expressions is central to AOP: Spring uses the AspectJ pointcut language by default.
Introduction: (Also known as an inter-type declaration). Declaring additional methods or fields on behalf of a type. Spring AOP allows you to introduce new interfaces (and a corresponding implementation) to any proxied object. For example, you could use an introduction to make a bean implement an IsModified interface, to simplify caching.
Target object: Object being advised by one or more aspects. Also referred to as the advised object. Since Spring AOP is implemented using runtime proxies, this object will always be a proxied object.
AOP proxy: An object created by the AOP framework in order to implement the aspect contracts (advise method executions and so on). In the Spring Framework, an AOP proxy will be a JDK dynamic proxy or a CGLIB proxy. Proxy creation is transparent to users of the schema-based and @AspectJ styles of aspect declaration introduced in Spring 2.0.
Weaving: Linking aspects with other application types or objects to create an advised object. This can be done at compile time (using the AspectJ compiler, for example), load time, or at runtime. Spring AOP, like other pure Java AOP frameworks, performs weaving at runtime.
Types of advice:
Before advice: Advice that executes before a join point, but which does not have the ability to prevent execution flow proceeding to the join point (unless it throws an exception).
After returning advice: Advice to be executed after a join point completes normally: for example, if a method returns without throwing an exception.
After throwing advice: Advice to be executed if a method exits by throwing an exception.
After (finally) advice: Advice to be executed regardless of the means by which a join point exits (normal or exceptional return).
Around advice: Advice that surrounds a join point such as a method invocation. This is the most powerful kind of advice. Around advice can perform custom behavior before and after the method invocation. It is also responsible for choosing whether to proceed to the join point or to shortcut the advised method execution by returning its own return value or throwing an exception.
Around advice is the most general kind of advice.
The concept of join points, matched by pointcuts, is the key to AOP which distinguishes it from older technologies offering only interception. Pointcuts enable advice to be targeted independently of the Object-Oriented hierarchy.
Finally, MVC - Model View Controller. When this pattern is done well, the views are extremely thin, and simply map the model to UI controls. This leaves what's left to test in the UI very small - just verifying that the model was mapped correctly, and perhaps that UI navigation proceeds through the expected flow inside the Controller. Why? Because the Model and your Controllers can all be unit and integration tested in isolation.
MVP and MVVM can fit into the “MVx” set of patterns with MVC. The differences between them are primarily around the dependency flow and cardinality.
The term MVVM was first mentioned by the WPF Architect, John Gossman, on his blog in 2005 [7]. It was then described in depths by Josh Smith in his MSDN article “WPF Apps with the Model-View-ViewModel Design Pattern” [8]. Gossman explains that the idea of MVVM was built around modern UI architecture where the View is the responsibly of the designer rather than the developer and therefore contains no code. Just like its MVC predecessor, the View in MVVM can bind to the data and display updates, but without any coding at all, just using XAML markup extensions. This way, the View is under the designer’s control, but can update its state from the domain classes using the WPF binding mechanism. This fits the description of the Presentation Model pattern.
This is why MVVM is similar to PM where the View will reference the Presentation Model, called ViewModel, which is a better name since it is a “Model of the View”. Unlike the Presentation Model, the ViewModel in MVVM also encapsulates commands just like the Presenter in MVP.
Overall, the View builds the UI and binds to the ViewModel
All three of these patterns allow us to design and architect for the Test Automation pyramid. An application that is built without these patterns - or one that has hard dependencies between layers and between layers and infrastructure code, and application logic riddled throughout the UI - can literally not have full test coverage in the ratios described by Cohn's pyramid. Use these patterns.
WHAT’S WRONG WITH THAT? Nothing. We’re all on the same team. We’re all interested in getting quality software, that does what our users want, into the hands of our users…
The Egyptians set the bar high - crafting a product that has lasted 4,500 years - what can we do to craft software with strength, integrity, and longevity?