Login

TestCase base class to easily temporarily change module values

Author:
SmileyChris
Posted:
July 15, 2010
Language:
Python
Version:
Not specified
Tags:
tests
Score:
0 (after 0 ratings)
  1. Base your test case off ModuleTestCase and set a class attribute containing a dictionary of modules which you want to be able to revert the values of.

  2. Use self.modulename.attribute = something in your setUp method or test cases to change the module's attribute values.

  3. The values will be automatically restored when each test case finishes.

For the common case of reverting the settings module, just use the SettingsTestCase as your base class.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
from django.conf import settings
from django.test import TestCase
from django.utils.importlib import import_module
 
 
def restore_attrs(wrapper):
    """
    Restore all attributes for a wrapped module to their original values
    (removing any which weren't originally set).
 
    """
    for key, value in wrapper._attrs_to_restore.iteritems():
        setattr(wrapper._wrapped_module, key, value)
    for setting in wrapper._delete_settings:
        try:
            delattr(wrapper._wrapped_module, setting)
        except AttributeError:
            pass
 
 
class ModuleWrapper(object):
    """
    A wrapper for modules which will remember attribute changes made so they
    can be reverted.
 
    """
 
    def __init__(self, module):
        """
        Initialise some containers to remember overwritten attributes to
        restore and newly added attributes to delete.
 
        """
        self.__dict__['_attrs_to_restore'] = {}
        self.__dict__['_attrs_to_delete'] = set()
        self.__dict__['_wrapped_module'] = module
 
    def __getattr__(self, key):
        """
        Retrieve an attribute.
 
        """
        getattr(self._wrapped_module, key)
 
    def __setattr__(self, key, value):
        """
        Change an attribute, remembering its original value so it can be
        reverted (or deleted if it didn't exist).
 
        """
        attrs_to_restore = self._attrs_to_restore
        try:
            if key not in attrs_to_restore:
                attrs_to_restore[key] = getattr(value, key)
        except AttributeError:
            self._attrs_to_delete.add(key)
        setattr(self._wrapped_module, key, value)
 
    def __delattr__(self, key):
        """
        Remove an attribute, remembering its original value so it can be
        restored.
        
        Deleting attributes which don't exist will *not* raise an exception.
 
        """
        try:
            if key not in self._attrs_to_delete and\
                            key not in self._attrs_to_restore:
                self._attrs_to_restore[key] = getattr(self._wrapped_module,
                                                      key)
            delattr(self._wrapped_module, key)
        except AttributeError:
            pass
 
 
class ModuleWrapperTestCase(TestCase):
    """
    A base test case that can be used to modify attributes in any number of
    modules under the knowledge that they will be returned to their original
    value (or removed if they didn't previously exist).
 
    To set which modules should be used, set the modules attribute on your test
    case subclass to a dictionary for modules which you would like to
    temporarily change attributes for.
    
    Each key should be the attribute which the wrapper will be available as and
    each value a module (or a dotted string representation of a module).
    
    For example::
 
        class MyTestCase(ModuleWrapperTestCase):
            modules = {'mymodule': myproject.mymodule}
            #...
 
    """
    modules = None
 
    def _pre_setup(self, *args, **kwargs):
        super(ModuleWrapperTestCase, self)._pre_setup(*args, **kwargs)
        if self.modules:
            for attr, module in self.modules.iteritems():
                if isinstance(module, basestring):
                    module = import_module(module)
                setattr(self, attr, ModuleWrapper(module))
 
    def _post_teardown(self, *args, **kwargs):
        if self.modules:
            for attr in self.modules:
                restore_attrs(getattr(self, attr))
        super(ModuleWrapperTestCase, self)._post_teardown(*args, **kwargs)
 
 
class SettingsTestCase(ModuleWrapperTestCase):
    """
    A base test case that can be used to modify settings in
    ``django.conf.settings`` under the knowledge that they will be returned
    to their original value (or removed if they didn't previously exist).
 
    """
    modules = {'settings': settings}
 
    def restore_settings(self):
        """
        Restore all settings to their original values (removing any which
        weren't originally in settings).
 
        """
        restore_attrs(self.settings)
        

More like this

  1. Run a testcase with custom INSTALLED_APPS by vdboor 2 years, 3 months ago
  2. Datetime widget by pigletto 7 years, 6 months ago
  3. Mod to allow simple_tag to access context by leaf 6 years, 5 months ago
  4. change settings locally in an individual test by akaihola 4 years, 6 months ago
  5. DKIM Email Backend by DrMeers 4 years, 10 months ago

Comments

Please login first before commenting.