Skip to content

Commit fe3c21b

Browse files
authored
Merge pull request faif#285 from gyermolenko/fix_constructor_inj_pattern
Combine and refine dependency injection patterns
2 parents e0e9bfc + fe7d3a1 commit fe3c21b

9 files changed

+114
-298
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ __Design for Testability Patterns__:
5757

5858
| Pattern | Description |
5959
|:-------:| ----------- |
60-
| [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) |
60+
| [dependency_injection](patterns/dependency_injection.py) | 3 variants of dependency injection |
6161

6262
__Fundamental Patterns__:
6363

patterns/dependency_injection.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#!/usr/bin/python
2+
# -*- coding : utf-8 -*-
3+
4+
"""
5+
Dependency Injection (DI) is a technique whereby one object supplies the dependencies (services)
6+
to another object (client).
7+
It allows to decouple objects: no need to change client code simply because an object it depends on
8+
needs to be changed to a different one. (Open/Closed principle)
9+
10+
Port of the Java example of Dependency Injection" in
11+
"xUnit Test Patterns - Refactoring Test Code" by Gerard Meszaros
12+
(ISBN-10: 0131495054, ISBN-13: 978-0131495050)
13+
14+
In the following example `time_provider` (service) is embedded into TimeDisplay (client).
15+
If such service performed an expensive operation you would like to substitute or mock it in tests.
16+
17+
class TimeDisplay(object):
18+
19+
def __init__(self):
20+
self.time_provider = datetime.datetime.now
21+
22+
def get_current_time_as_html_fragment(self):
23+
current_time = self.time_provider()
24+
current_time_as_html_fragment = "<span class=\"tinyBoldText\">{}</span>".format(current_time)
25+
return current_time_as_html_fragment
26+
27+
"""
28+
29+
import datetime
30+
31+
32+
class ConstructorInjection(object):
33+
34+
def __init__(self, time_provider):
35+
self.time_provider = time_provider
36+
37+
def get_current_time_as_html_fragment(self):
38+
current_time = self.time_provider()
39+
current_time_as_html_fragment = "<span class=\"tinyBoldText\">{}</span>".format(current_time)
40+
return current_time_as_html_fragment
41+
42+
43+
class ParameterInjection(object):
44+
45+
def __init__(self):
46+
pass
47+
48+
def get_current_time_as_html_fragment(self, time_provider):
49+
current_time = time_provider()
50+
current_time_as_html_fragment = "<span class=\"tinyBoldText\">{}</span>".format(current_time)
51+
return current_time_as_html_fragment
52+
53+
54+
class SetterInjection(object):
55+
"""Setter Injection"""
56+
57+
def __init__(self):
58+
pass
59+
60+
def set_time_provider(self, time_provider):
61+
self.time_provider = time_provider
62+
63+
def get_current_time_as_html_fragment(self):
64+
current_time = self.time_provider()
65+
current_time_as_html_fragment = "<span class=\"tinyBoldText\">{}</span>".format(current_time)
66+
return current_time_as_html_fragment
67+
68+
69+
def production_code_time_provider():
70+
"""
71+
Production code version of the time provider (just a wrapper for formatting
72+
datetime for this example).
73+
"""
74+
current_time = datetime.datetime.now()
75+
current_time_formatted = "{}:{}".format(current_time.hour, current_time.minute)
76+
return current_time_formatted
77+
78+
79+
def midnight_time_provider():
80+
"""Hard-coded stub"""
81+
return "24:01"
82+
83+
84+
def main():
85+
"""
86+
>>> time_with_ci1 = ConstructorInjection(midnight_time_provider)
87+
>>> time_with_ci1.get_current_time_as_html_fragment()
88+
'<span class="tinyBoldText">24:01</span>'
89+
90+
>>> time_with_ci2 = ConstructorInjection(production_code_time_provider)
91+
>>> time_with_ci2.get_current_time_as_html_fragment()
92+
'<span class="tinyBoldText">...</span>'
93+
94+
>>> time_with_pi = ParameterInjection()
95+
>>> time_with_pi.get_current_time_as_html_fragment(midnight_time_provider)
96+
'<span class="tinyBoldText">24:01</span>'
97+
98+
>>> time_with_si = SetterInjection()
99+
100+
>>> time_with_si.get_current_time_as_html_fragment()
101+
Traceback (most recent call last):
102+
...
103+
AttributeError: 'SetterInjection' object has no attribute 'time_provider'
104+
105+
>>> time_with_si.set_time_provider(midnight_time_provider)
106+
>>> time_with_si.get_current_time_as_html_fragment()
107+
'<span class="tinyBoldText">24:01</span>'
108+
"""
109+
110+
111+
if __name__ == "__main__":
112+
import doctest
113+
doctest.testmod(optionflags=doctest.ELLIPSIS)

patterns/dft/__init__.py

Whitespace-only changes.

patterns/dft/constructor_injection.py

Lines changed: 0 additions & 53 deletions
This file was deleted.

patterns/dft/parameter_injection.py

Lines changed: 0 additions & 54 deletions
This file was deleted.

patterns/dft/setter_injection.py

Lines changed: 0 additions & 57 deletions
This file was deleted.

tests/dft/test_constructor_injection.py

Lines changed: 0 additions & 41 deletions
This file was deleted.

tests/dft/test_parameter_injection.py

Lines changed: 0 additions & 46 deletions
This file was deleted.

0 commit comments

Comments
 (0)