I want to mock out methods on any instance of some class in the production code in order to facilitate testing. Is there any library in Python which could facilitate this?>
I don't know Ruby quite well enough to tell exactly what you're trying to do, but check out the __getattr__ method. If you define it in your class, Python will call it when code tries to access any attribute of your class that isn't otherwise defined. Since you want it to be a method, it will need to create a method on the fly that it returns.
>>> class Product:
... def __init__(self, number):
... self.number = number
... def get_number(self):
... print "My number is %d" % self.number
... def __getattr__(self, attr_name):
... return lambda:"stubbed_"+attr_name
...
>>> p = Product(172)
>>> p.number
172
>>> p.name()
'stubbed_name'
>>> p.get_number()
My number is 172
>>> p.other_method()
'stubbed_other_method'
Also note that __getattr__ needs to not use any other undefined attributes of your class, or else it will be infinitely recursive, calling __getattr__ for the attribute that doesn't exist.
... def __getattr__(self, attr_name):
... return self.x
>>> p.y
Traceback (most recent call last):
#clipped
RuntimeError: maximum recursion depth exceeded while calling a Python object
If this is something you only want to do from your test code, not the production code, then put your normal class definition in the production code file, then in the test code define the __getattr__ method (unbound), and then bind it to the class you want:
#production code
>>> class Product:
... def __init__(self, number):
... self.number = number
... def get_number(self):
... print "My number is %d" % self.number
...
#test code
>>> def __getattr__(self, attr):
... return lambda:"stubbed_"+attr_name
...
>>> p = Product(172)
>>> p.number
172
>>> p.name()
Traceback (most recent call last):
File "", line 1, in
AttributeError: Product instance has no attribute 'name'
>>> Product.__getattr__ = __getattr__
>>> p.name()
'stubbed_name'
I'm not sure how this would react with a class that was already using __getattribute__ (as opposed to __getattr__, __getattribute__ is called for all attributes whether or not they exist).
If you only want to do this for specific methods that already exist, then you could do something like:
#production code
>>> class Product:
... def __init__(self, number):
... self.number = number
... def get_number(self):
... return self.number
...
>>> p = Product(172)
>>> p.get_number()
172
#test code
>>> def get_number(self):
... return "stub_get_number"
...
>>> Product.get_number = get_number
>>> p.get_number()
'stub_get_number'
Or if you really wanted to be elegant, you could create a wrapper function to make doing multiple methods easy:
#test code
>>> import functools
>>> def stubber(fn):
... return functools.wraps(fn)(lambda self:"stub_"+fn.__name__)
...
>>> Product.get_number = stubber(Product.get_number)
>>> p.get_number()
'stub_get_number'