Stupid Python tricks: Using 'with' for mocking
Python's with
statement just begs to be used for mocking. Consider this little "context manager":
class Mock(object): def __init__(self, target, attr, replacement): self.target = target self.attr = attr self.replacement = replacement def __enter__(self): self.old_value = getattr(self.target, self.attr) setattr(self.target, self.attr, self.replacement) return self def __exit__(self, type, value, traceback): setattr(self.target, self.attr, self.old_value) return type is None
This can be used to temporarily replace any attribute:
# assume a module config with a function get_configuration() with Mock(config, 'get_configuration', lambda: my_fake_config): ...do stuff...
And so on.
Thoughts:
1. The with
statement has been around for a few years now, so this has probably been done a thousand times before. I'll catch up with the current state of the art eventually. ;-)
(I stumbled upon this because the test suite used at my work uses minimock, which worked fine until we started porting code to IronPython. Minimock uses a call to inspect.stack()
which is apparently unsupported by IronPython 2.6. I'm not sure when this would be fixed, or if it's even fixable at all; maybe getting stack frame info is not possible at all, I don't know. So, I ended up replacing some of the instances where minimock was used, with my own constructs.)
2. I cannot help but noticing that in some other languages, you can just write a with statement (and much more) without having to wait until special syntax is added to the language. Looking through Scheme-, Io- or even Ruby-colored glasses, "with" is just something you can add if you need it, using either macros (in Scheme) or blocks (in Io and Ruby). Python doesn't have first-class code blocks, so you'll have to wait until something like with
is added to the language. Unfortunately even with
is no substitute for real code blocks, since you have no control over the block itself. :-(
The standard replies from the Python community would be "YAGNI" or "too much syntactic flexibility would make code less readable". I might have agreed five years ago; I'm not so sure about that anymore nowadays.