diff --git a/README.md b/README.md
index ebc2b669..20739846 100644
--- a/README.md
+++ b/README.md
@@ -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__:
diff --git a/patterns/dependency_injection.py b/patterns/dependency_injection.py
new file mode 100644
index 00000000..06dee725
--- /dev/null
+++ b/patterns/dependency_injection.py
@@ -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 = "{}".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 = "{}".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 = "{}".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 = "{}".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()
+ '24:01'
+
+ >>> time_with_ci2 = ConstructorInjection(production_code_time_provider)
+ >>> time_with_ci2.get_current_time_as_html_fragment()
+ '...'
+
+ >>> time_with_pi = ParameterInjection()
+ >>> time_with_pi.get_current_time_as_html_fragment(midnight_time_provider)
+ '24:01'
+
+ >>> 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()
+ '24:01'
+ """
+
+
+if __name__ == "__main__":
+ import doctest
+ doctest.testmod(optionflags=doctest.ELLIPSIS)
diff --git a/patterns/dft/__init__.py b/patterns/dft/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/patterns/dft/constructor_injection.py b/patterns/dft/constructor_injection.py
deleted file mode 100644
index 7194a2ea..00000000
--- a/patterns/dft/constructor_injection.py
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/python
-# -*- coding : utf-8 -*-
-import datetime
-
-"""
-Port of the Java example of "Constructor Injection" in
-"xUnit Test Patterns - Refactoring Test Code" by Gerard Meszaros
-(ISBN-10: 0131495054, ISBN-13: 978-0131495050)
-
-production code which is untestable:
-
-class TimeDisplay(object):
-
- def __init__(self):
- self.time_provider = datetime.datetime
-
- def get_current_time_as_html_fragment(self):
- current_time = self.time_provider.now()
- current_time_as_html_fragment = "{}".format(current_time)
- return current_time_as_html_fragment
-"""
-
-
-class TimeDisplay(object):
- def __init__(self, time_provider):
- self.time_provider = time_provider
-
- def get_current_time_as_html_fragment(self):
- current_time = self.time_provider.now()
- current_time_as_html_fragment = "{}".format(current_time)
- return current_time_as_html_fragment
-
-
-class ProductionCodeTimeProvider(object):
- """
- Production code version of the time provider (just a wrapper for formatting
- datetime for this example).
- """
-
- def now(self):
- current_time = datetime.datetime.now()
- current_time_formatted = "{}:{}".format(current_time.hour, current_time.minute)
- return current_time_formatted
-
-
-class MidnightTimeProvider(object):
- """
- Class implemented as hard-coded stub (in contrast to configurable stub).
- """
-
- def now(self):
- current_time_is_always_midnight = "24:01"
- return current_time_is_always_midnight
diff --git a/patterns/dft/parameter_injection.py b/patterns/dft/parameter_injection.py
deleted file mode 100644
index c1592736..00000000
--- a/patterns/dft/parameter_injection.py
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/python
-# -*- coding : utf-8 -*-
-import datetime
-
-"""
-Port of the Java example of "Parameter Injection" in
-"xUnit Test Patterns - Refactoring Test Code" by Gerard Meszaros
-(ISBN-10: 0131495054, ISBN-13: 978-0131495050) accessible in outdated version on
-http://xunitpatterns.com/Dependency%20Injection.html.
-
-production code which is untestable:
-
-class TimeDisplay(object):
-
- def __init__(self):
- self.time_provider = datetime.datetime
-
- def get_current_time_as_html_fragment(self):
- current_time = self.time_provider.now()
- current_time_as_html_fragment = "{}".format(current_time)
- return current_time_as_html_fragment
-"""
-
-
-class TimeDisplay(object):
- def __init__(self):
- pass
-
- def get_current_time_as_html_fragment(self, time_provider):
- current_time = time_provider.now()
- current_time_as_html_fragment = "{}".format(current_time)
- return current_time_as_html_fragment
-
-
-class ProductionCodeTimeProvider(object):
- """
- Production code version of the time provider (just a wrapper for formatting
- datetime for this example).
- """
-
- def now(self):
- current_time = datetime.datetime.now()
- current_time_formatted = "{}:{}".format(current_time.hour, current_time.minute)
- return current_time_formatted
-
-
-class MidnightTimeProvider(object):
- """
- Class implemented as hard-coded stub (in contrast to configurable stub).
- """
-
- def now(self):
- current_time_is_always_midnight = "24:01"
- return current_time_is_always_midnight
diff --git a/patterns/dft/setter_injection.py b/patterns/dft/setter_injection.py
deleted file mode 100644
index f14a2a24..00000000
--- a/patterns/dft/setter_injection.py
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/usr/bin/python
-# -*- coding : utf-8 -*-
-import datetime
-
-"""
-Port of the Java example of "Setter Injection" in
-"xUnit Test Patterns - Refactoring Test Code" by Gerard Meszaros
-(ISBN-10: 0131495054, ISBN-13: 978-0131495050) accessible in outdated version on
-http://xunitpatterns.com/Dependency%20Injection.html.
-
-production code which is untestable:
-
-class TimeDisplay(object):
-
- def __init__(self):
- self.time_provider = datetime.datetime
-
- def get_current_time_as_html_fragment(self):
- current_time = self.time_provider.now()
- current_time_as_html_fragment = "{}".format(current_time)
- return current_time_as_html_fragment
-"""
-
-
-class TimeDisplay(object):
- 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.now()
- current_time_as_html_fragment = "{}".format(current_time)
- return current_time_as_html_fragment
-
-
-class ProductionCodeTimeProvider(object):
- """
- Production code version of the time provider (just a wrapper for formatting
- datetime for this example).
- """
-
- def now(self):
- current_time = datetime.datetime.now()
- current_time_formatted = "{}:{}".format(current_time.hour, current_time.minute)
- return current_time_formatted
-
-
-class MidnightTimeProvider(object):
- """
- Class implemented as hard-coded stub (in contrast to configurable stub).
- """
-
- def now(self):
- current_time_is_always_midnight = "24:01"
- return current_time_is_always_midnight
diff --git a/tests/dft/test_constructor_injection.py b/tests/dft/test_constructor_injection.py
deleted file mode 100644
index 6ee83601..00000000
--- a/tests/dft/test_constructor_injection.py
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-import unittest
-
-from patterns.dft.constructor_injection import TimeDisplay, MidnightTimeProvider, ProductionCodeTimeProvider, datetime
-
-"""
-Port of the Java example of "Constructor Injection" in
-"xUnit Test Patterns - Refactoring Test Code" by Gerard Meszaros
-(ISBN-10: 0131495054, ISBN-13: 978-0131495050)
-
-Test code which will almost always fail (if not exactly 12:01) when untestable
-production code (production code time provider is datetime) is used:
-
- def test_display_current_time_at_midnight(self):
- class_under_test = TimeDisplay()
- expected_time = "24:01"
- result = class_under_test.get_current_time_as_as_html_fragment()
- self.assertEqual(result, expected_time)
-"""
-
-
-class ConstructorInjectionTest(unittest.TestCase):
- def test_display_current_time_at_midnight(self):
- """
- Will almost always fail (despite of right at/after midnight).
- """
- time_provider_stub = MidnightTimeProvider()
- class_under_test = TimeDisplay(time_provider_stub)
- expected_time = "24:01"
- self.assertEqual(class_under_test.get_current_time_as_html_fragment(), expected_time)
-
- def test_display_current_time_at_current_time(self):
- """
- Just as justification for working example. (Will always pass.)
- """
- production_code_time_provider = ProductionCodeTimeProvider()
- class_under_test = TimeDisplay(production_code_time_provider)
- current_time = datetime.datetime.now()
- expected_time = "{}:{}".format(current_time.hour, current_time.minute)
- self.assertEqual(class_under_test.get_current_time_as_html_fragment(), expected_time)
diff --git a/tests/dft/test_parameter_injection.py b/tests/dft/test_parameter_injection.py
deleted file mode 100644
index da340b93..00000000
--- a/tests/dft/test_parameter_injection.py
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-import unittest
-
-from patterns.dft.parameter_injection import TimeDisplay, MidnightTimeProvider, ProductionCodeTimeProvider, datetime
-
-"""
-Port of the Java example of "Parameter Injection" in
-"xUnit Test Patterns - Refactoring Test Code" by Gerard Meszaros
-(ISBN-10: 0131495054, ISBN-13: 978-0131495050) accessible in outdated version on
-http://xunitpatterns.com/Dependency%20Injection.html.
-
-Test code which will almost always fail (if not exactly 12:01) when untestable
-production code (have a look into constructor_injection.py) is used:
-
- def test_display_current_time_at_midnight(self):
- class_under_test = TimeDisplay()
- expected_time = "24:01"
- result = class_under_test.get_current_time_as_as_html_fragment()
- self.assertEqual(result, expected_time)
-"""
-
-
-class ParameterInjectionTest(unittest.TestCase):
- def test_display_current_time_at_midnight(self):
- """
- Would almost always fail (despite of right at/after midnight) if
- untestable production code would have been used.
- """
- time_provider_stub = MidnightTimeProvider()
- class_under_test = TimeDisplay()
- expected_time = "24:01"
- self.assertEqual(class_under_test.get_current_time_as_html_fragment(time_provider_stub), expected_time)
-
- def test_display_current_time_at_current_time(self):
- """
- Just as justification for working example with the time provider used in
- production. (Will always pass.)
- """
- production_code_time_provider = ProductionCodeTimeProvider()
- class_under_test = TimeDisplay()
- current_time = datetime.datetime.now()
- expected_time = "{}:{}".format(current_time.hour, current_time.minute)
- self.assertEqual(
- class_under_test.get_current_time_as_html_fragment(production_code_time_provider), expected_time
- )
diff --git a/tests/dft/test_setter_injection.py b/tests/dft/test_setter_injection.py
deleted file mode 100644
index fce7b2c9..00000000
--- a/tests/dft/test_setter_injection.py
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-import unittest
-
-from patterns.dft.setter_injection import TimeDisplay, MidnightTimeProvider, ProductionCodeTimeProvider, datetime
-
-"""
-Port of the Java example of "Setter Injection" in
-"xUnit Test Patterns - Refactoring Test Code" by Gerard Meszaros
-(ISBN-10: 0131495054, ISBN-13: 978-0131495050) accessible in outdated version on
-http://xunitpatterns.com/Dependency%20Injection.html.
-
-Test code which will almost always fail (if not exactly 12:01) when untestable
-production code (have a look into constructor_injection.py) is used:
-
- def test_display_current_time_at_midnight(self):
- class_under_test = TimeDisplay()
- expected_time = "24:01"
- result = class_under_test.get_current_time_as_as_html_fragment()
- self.assertEqual(result, expected_time)
-"""
-
-
-class ParameterInjectionTest(unittest.TestCase):
- def test_display_current_time_at_midnight(self):
- """
- Would almost always fail (despite of right at/after midnight) if
- untestable production code would have been used.
- """
- time_provider_stub = MidnightTimeProvider()
- class_under_test = TimeDisplay()
- class_under_test.set_time_provider(time_provider_stub)
- expected_time = "24:01"
- self.assertEqual(class_under_test.get_current_time_as_html_fragment(), expected_time)
-
- def test_display_current_time_at_current_time(self):
- """
- Just as justification for working example with the time provider used in
- production. (Will always pass.)
- """
- production_code_time_provider = ProductionCodeTimeProvider()
- class_under_test = TimeDisplay()
- class_under_test.set_time_provider(production_code_time_provider)
- current_time = datetime.datetime.now()
- expected_time = "{}:{}".format(current_time.hour, current_time.minute)
- self.assertEqual(class_under_test.get_current_time_as_html_fragment(), expected_time)