Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Mock Objects, Design and Dependency Inversion Principle
1. Mock Objects,
Design and
Dependency Inverting Principle
P. Heinonen 2011
2. What are mock objects?
• Object oriented crash test dummies
• In a unit test mock objects can simulate the
behavior of complex, real (non-mock) objects
• technique that allow you to isolate classes from
their dependencies for testing purposes.
• allows fine-grained testing even before the
dependent classes are fully implemented
• normal assertion in unit test verifies the state but
with Mock objects test verifies behavior
• many practices in TDD and BDD
3. Mocks and Stubs
• A mock is an object that
– can have expectations
– will verify that the expected actions have indeed occurred.
– Is pre-programmed with expectations which form a specification of the calls they are expected
to receive
• A stub is an object that
– you use in order to pass to the code under test.
– which you can setup expectations, so it would act in certain ways, but those expectations will
never be verified. A stub's properties will automatically behave like normal properties, and
you can't set expectations on them.
– provide canned answers to calls made during the test, usually not responding at all to anything
outside what's programmed in for the test.
• If you want to verify the behavior of the system under test, you will use a mock
with the appropriate expectation, and verify that. If you want just to pass a value
that may need to act in a certain way, but isn't the focus of this test, you will use a
stub.
IMPORTANT: A stub will never cause a test to fail.
4. When to mock?
• when creating effective unit tests
• when testing object behaving
• when a real object is impractical or impossible to incorporate into a
unit test
• For example in cases where real-object:
– supplies non-deterministic results (e.g., the current time or the
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
before the test)
– 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)
5. Unit test principles
• Test only one thing per test
• each unit test should validate no more than
one significant interaction with another
object. This generally implies that a given test
should have no more than one mock object,
but it may have several stubs, as needed
• Unit test is test which is only in memory, is fast
and repeatable and does not touch in any
external resources
6. Mocking drives your design
• Mocks force you to think dependencies that
your classes and methods have.
• It forces to think about coupling between
classes and drives the design to better one.
• Loosely coupled design makes testing and
using Mock objects much easier.
• Thinking design early helps you to easily
manage code changes over time.
8. Unit test with Rhino Mock
[Test(Description = @"Registering new call and saves the call to the CallRepository")]
public void RegisterNewWorkshopCall_SaveTheCall_WhenCallIsValid()
{
// There should be three steps in good unit test: Arrange, Act, Assert. "AAA syntax"
// First you arrange the state, then you execute the code under test and
// finally you assert that the expected state change or behavior happened.
// ARRANGE
ICallRepository mockCallRepository = MockRepository.GenerateMock<ICallRepository>();
ICallValidator mockCallValidator = MockRepository.GenerateMock<ICallValidator>();
// controlling program flow by specifying stub
mockCallValidator.Stub(x => x.IsValid(Arg<Call>.Is.Anything)).Return(true);
// create SUT (System Under Test with dependency Injecting two mocks)
var callRegistrationService = new CallRegistrationService(mockCallRepository, mockCallValidator);
var call = new Call{Id = 123,Gateway = Gateway.EOBD,Parameter = new Parameter()};
// ACT
callRegistrationService.RegisterNewCall(call);
// ASSERT
mockCallRepository.AssertWasCalled(x => x.Save(call));
}
9. For the sake of good design
• Good design is better than bad design
• Loosely coupled objects are usually a better
design than tightly coupled objects
• Testing improves code quality and developer
efficiency over time
• Testing is easier with a loosely coupled designs
• Managing changes are easier when you have
good sets of unit tests
10. Dependency Inversion Principle
• Inverting the design where lower level modules
defining interface that higher level modules depend
on.
• So we get; higher level modules which define
interfaces that lower level modules implement
”High-level modules should not depend on low-
level modules. Both should depend on
abstractions. Abstraction should not depend upon
details. Details should depend upon abstractions.”
- Founder of SOLID principles, Bob Martin
11. Problem
High level class have to be changed and updated every time the low-level-class interface
is changed, added or removed. So, High level class is not reusable when low-level-classes
defines interfaces which high level class is depended on.
High Level Class
Higher layer
Interface Interface
Lower layer
Low Level Class Low Level Class
12. Solution: Inverting Dependency
High level class defines interface which low-level-classes implement.
Basically what High level class tells to low-level-classes is that:
”you have to implement this interface if I’m going to use you to do this job”.
Also, now it is possible to add more low-level implementation without changing
the High level classHigh level class becomes reusable.
High Level Class Interface
Higher layer
Low Level Class
Low Level Class
Low Level Class
Lower layer Low Level Class
14. Inversion of Control
• ”IoC” is a high level practice and design guideline for removing
dependencies in your code.
• aka. Hollywood principle: ”Don’t call us, we call you”
• Can be used in different ways
– Control over interface between two systems or components
– Control over the flow of an application
– Control over dependency creation and binding
• Serves the following purposes:
– There is a decoupling of the execution of a certain task from
implementation.
– Every module can focus on what it is designed for.
– Modules make no assumptions about what other systems do but rely
on their contracts.
– Replacing modules has no side effect on other modules.
15. Example of IoC patterns
• Dependency Inversion Principle ”DIP”
• Interface Inversion
• Flow Inversion (not explained here)
• Create Inversion
16. Interface Inversion
This is anti-pattern: Don’t over use Interfaces
IHuman GameOfLife
Human
IElephant
Elephant
IGiraffe
Giraffe
19. Creation Inversion
• Reduce use of switch-statements, eh more than
that...
• Normally you create object like:
– MyClass mObject = new MyClass();
• Or with interface:
– IMyInterface myObject = new MyImplementation();
• With inverting control you will...
– Create object outside of the class they are being used
– Create objects outside of objects in some central
place, like a factory patternavoid copy&paste
coding and tight dependencies+maintenance horror
20. Some Creation Inversion types
• Factory Pattern
– Payment payment = InvoiceFactory.CreatePayment();
• Service Locator
– Payment payment = ServiceLocator.Create(IPayment);
• Dependency Injection ”DI”
– Payment payment = GetThePayment();
– InvoiceController controller = new InvoiceController(payment);
– Moves the creation and binding of a dependency outside of the class
that depends on it. Common way to create loose coupling
21. Use common sense with DI
• Dependency Injection drives to good design
but it has also cons and caveats when using
too much:
– Dependency Injection would expose internal
implementation of class
– DI also violates encapsulation
– Dependencies created before needed
– Large object graphs
• So, Watch out for too many dependencies!
22. Summary
• Depency Inversion Principle ”DIP” is a principle to
guide software design to think dependencies between
higher and lower level modules.
• IoC is a set of practices and patterns which help us to
achieve the ”DIP” and see the benefits of changing
dependencies.
• Think before using IoC; do you have good reason, what
kind of dependency inversion you need and why?
• Every time using IoC you are inverting the Control in
your design and that mean that you are taking control
out of objects and interfaces or some other ways
changing the control.