improved proxy implementation.
proxy must now contain all public methods that the subject has.
This commit is contained in:
@@ -1,4 +1,7 @@
|
|||||||
class Proxy(object):
|
from abc import ABCMeta
|
||||||
|
|
||||||
|
|
||||||
|
class Proxy(object, metaclass=ABCMeta):
|
||||||
"""
|
"""
|
||||||
Base Proxy class as part of the Proxy design pattern.
|
Base Proxy class as part of the Proxy design pattern.
|
||||||
"""
|
"""
|
||||||
@@ -9,6 +12,22 @@ class Proxy(object):
|
|||||||
@param subject: The real subject this proxy calls upon.
|
@param subject: The real subject this proxy calls upon.
|
||||||
"""
|
"""
|
||||||
self._subject = subject
|
self._subject = subject
|
||||||
|
self._validate()
|
||||||
|
|
||||||
|
def _validate(self):
|
||||||
|
"""
|
||||||
|
Validate that the subject and this proxy follow the same interface.
|
||||||
|
|
||||||
|
@raise AttributeError: If the subject and this proxy do not follow the same interface.
|
||||||
|
"""
|
||||||
|
for attr in dir(self._subject):
|
||||||
|
if attr.startswith('_') or attr.startswith('__'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
elif not callable(getattr(self._subject, attr, None)) or not callable(getattr(self, attr, None)):
|
||||||
|
raise AttributeError('Subject and Proxy must follow same interface')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,15 @@ class ProxyTestCase(TestCase):
|
|||||||
def __init__(self, age):
|
def __init__(self, age):
|
||||||
self.age = age
|
self.age = age
|
||||||
|
|
||||||
|
self.car = Car()
|
||||||
|
self.driver = Driver(17)
|
||||||
|
|
||||||
|
def test_valid_proxy(self):
|
||||||
|
"""
|
||||||
|
Test a Proxy class following the same interface as the subject.
|
||||||
|
|
||||||
|
@raise AssertionError: If the test fails.
|
||||||
|
"""
|
||||||
class ProxyCar(Proxy):
|
class ProxyCar(Proxy):
|
||||||
|
|
||||||
def __init__(self, subject, driver):
|
def __init__(self, subject, driver):
|
||||||
@@ -32,14 +41,25 @@ class ProxyTestCase(TestCase):
|
|||||||
else:
|
else:
|
||||||
return 'Driver is too young to drive'
|
return 'Driver is too young to drive'
|
||||||
|
|
||||||
self.proxy = ProxyCar(Car(), Driver(17))
|
try:
|
||||||
|
proxy = ProxyCar(self.car, self.driver)
|
||||||
|
except AttributeError:
|
||||||
|
raise AssertionError()
|
||||||
|
else:
|
||||||
|
self.assertEqual('drive car', proxy.drive_car())
|
||||||
|
proxy.driver.age = 15
|
||||||
|
self.assertEqual('Driver is too young to drive', proxy.drive_car())
|
||||||
|
|
||||||
def test_drive_car(self):
|
def test_invalid_proxy(self):
|
||||||
"""
|
"""
|
||||||
Test the proxy with the drive car method.
|
Test a Proxy class that is not following the same interface as the subject.
|
||||||
|
|
||||||
@raise AssertionError: If the test fails.
|
@raise AssertionError: If the test fails.
|
||||||
"""
|
"""
|
||||||
self.assertEqual('drive car', self.proxy.drive_car())
|
class ProxyCar(Proxy):
|
||||||
self.proxy.driver.age = 15
|
|
||||||
self.assertEqual('Driver is too young to drive', self.proxy.drive_car())
|
def __init__(self, subject, driver):
|
||||||
|
super().__init__(subject)
|
||||||
|
self.driver = driver
|
||||||
|
|
||||||
|
self.assertRaises(AttributeError, lambda: ProxyCar(self.car, self.driver))
|
||||||
|
|||||||
Reference in New Issue
Block a user