A testable singleton decorator
Project description
singleton-decorator
A testable singleton decorator allows easily create a singleton objects just adding a decorator to class definition but also allows easily write unit tests for those classes.
A problem
If you use a simple singleton pattern based on a decorator function that wraps a class with inner wrapper function like this:
def singleton(cls):
instances = {}
def wrapper(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return wrapper
it works fine with your classes, but it makes impossible a direct access to the class object without decorator. So you cannot call methods using a class name in unit tests:
@singleton
class YourClass:
def method(self):
...
YourClass.method(...)
this code would not work because YouClass actually contains a wrapper function but not your class object. Also this approach causes another problem if your tests require separate instances of the objects, so a singleton pattern could break an isolation of different tests.
Solution
The singleton-decorator offers a simple solution to avoid both of these problems. It uses a separate wrapper object for each decorated class and holds a class within __wrapped__ attribute so you can access the decorated class directly in your unit tests.
Installation
To install the singleton-decorator just type in the command line:
$ pip install singleton-decorator
Usage
At first import the singleton decorator:
from singleton_decorator import singleton
Then decorate you classes with this decorator:
@singleton
class YourClass:
...
That’s all. Now you could create or get existing instance of your class by calling it as a simple class object:
obj = YourClass() # creates a new instance
obj2 = YourClass() # returns the same instance
obj3 = YourClass() # returns the same instance
...
You also could pass args and kwargs into constructor of your class:
obj = YourClass(1, "foo", bar="baz")
Unit testing
In your unit tests to run the methods of decorated classes in isolation without instantiation the object (to avoid running a constructor code), use the __wrapped__ attribute of the wrapper object:
# your_module.py
@singleton
class YourClass:
def your_method(self):
...
# tests.py
class TestYourClass(TestCase):
def test_your_method(self):
obj = mock.MagicMock()
YourClass.__wrapped__.your_method(obj)
...
This test runs a code of the your_method only using a mock object as the self argument, so the test would be run in complete isolation and would not depend on another pieces of your code including a constructor method.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Hashes for singleton-decorator-1.0.0.tar.gz
Algorithm | Hash digest | |
---|---|---|
SHA256 | 1a90ad8a8a738be591c9c167fdd677c5d4a43d1bc6b1c128227be1c5e03bee07 |
|
MD5 | 9b0011c7d33a671bc02b58362ef3dc18 |
|
BLAKE2b-256 | 3398a8b5c919bee1152a9a1afd82014431f8db5882699754de50d1b3aba4d136 |