Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ __Design for Testability Patterns__:

| Pattern | Description |
|:-------:| ----------- |
| [setter_injection](patterns/dft/setter_injection.py) | the client provides the depended-on object to the SUT via the setter injection (implementation variant of dependency injection) |
| [dependency_injection](patterns/dependency_injection.py) | 3 variants of dependency injection |

__Fundamental Patterns__:

Expand Down
113 changes: 113 additions & 0 deletions patterns/dependency_injection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#!/usr/bin/python
# -*- coding : utf-8 -*-

"""
Dependency Injection (DI) is a technique whereby one object supplies the dependencies (services)
to another object (client).
It allows to decouple objects: no need to change client code simply because an object it depends on
needs to be changed to a different one. (Open/Closed principle)

Port of the Java example of Dependency Injection" in
"xUnit Test Patterns - Refactoring Test Code" by Gerard Meszaros
(ISBN-10: 0131495054, ISBN-13: 978-0131495050)

In the following example `time_provider` (service) is embedded into TimeDisplay (client).
If such service performed an expensive operation you would like to substitute or mock it in tests.

class TimeDisplay(object):

def __init__(self):
self.time_provider = datetime.datetime.now

def get_current_time_as_html_fragment(self):
current_time = self.time_provider()
current_time_as_html_fragment = "<span class=\"tinyBoldText\">{}</span>".format(current_time)
return current_time_as_html_fragment

"""

import datetime


class ConstructorInjection(object):

def __init__(self, time_provider):
self.time_provider = time_provider

def get_current_time_as_html_fragment(self):
current_time = self.time_provider()
current_time_as_html_fragment = "<span class=\"tinyBoldText\">{}</span>".format(current_time)
return current_time_as_html_fragment


class ParameterInjection(object):

def __init__(self):
pass

def get_current_time_as_html_fragment(self, time_provider):
current_time = time_provider()
current_time_as_html_fragment = "<span class=\"tinyBoldText\">{}</span>".format(current_time)
return current_time_as_html_fragment


class SetterInjection(object):
"""Setter Injection"""

def __init__(self):
pass

def set_time_provider(self, time_provider):
self.time_provider = time_provider

def get_current_time_as_html_fragment(self):
current_time = self.time_provider()
current_time_as_html_fragment = "<span class=\"tinyBoldText\">{}</span>".format(current_time)
return current_time_as_html_fragment


def production_code_time_provider():
"""
Production code version of the time provider (just a wrapper for formatting
datetime for this example).
"""
current_time = datetime.datetime.now()
current_time_formatted = "{}:{}".format(current_time.hour, current_time.minute)
return current_time_formatted


def midnight_time_provider():
"""Hard-coded stub"""
return "24:01"


def main():
"""
>>> time_with_ci1 = ConstructorInjection(midnight_time_provider)
>>> time_with_ci1.get_current_time_as_html_fragment()
'<span class="tinyBoldText">24:01</span>'

>>> time_with_ci2 = ConstructorInjection(production_code_time_provider)
>>> time_with_ci2.get_current_time_as_html_fragment()
'<span class="tinyBoldText">...</span>'

>>> time_with_pi = ParameterInjection()
>>> time_with_pi.get_current_time_as_html_fragment(midnight_time_provider)
'<span class="tinyBoldText">24:01</span>'

>>> time_with_si = SetterInjection()

>>> time_with_si.get_current_time_as_html_fragment()
Traceback (most recent call last):
...
AttributeError: 'SetterInjection' object has no attribute 'time_provider'

>>> time_with_si.set_time_provider(midnight_time_provider)
>>> time_with_si.get_current_time_as_html_fragment()
'<span class="tinyBoldText">24:01</span>'
"""


if __name__ == "__main__":
import doctest
doctest.testmod(optionflags=doctest.ELLIPSIS)
Empty file removed patterns/dft/__init__.py
Empty file.
53 changes: 0 additions & 53 deletions patterns/dft/constructor_injection.py

This file was deleted.

54 changes: 0 additions & 54 deletions patterns/dft/parameter_injection.py

This file was deleted.

57 changes: 0 additions & 57 deletions patterns/dft/setter_injection.py

This file was deleted.

41 changes: 0 additions & 41 deletions tests/dft/test_constructor_injection.py

This file was deleted.

46 changes: 0 additions & 46 deletions tests/dft/test_parameter_injection.py

This file was deleted.

Loading