I came across a strange bahviour of the patch
decorator in Fudge 1.0.3. It does not patch the module when importing classes via
from <module> import <class>
but works fine when importing
import <module>
with the corresponding code adaption.
Here's a minimalized setup:
mdle.py:
class Klaas(object):
def __init__(self):
# easyest way to signal this class has been instantiated accidently
raise Exception(">:[")
some.py (test not working):
from mdle import Klaas()
def instantiate():
instance = Klaas()
some.py (test working):
import mdle
def instantiate():
instance = mdle.Klaas()
some_test.py:
import unittest
import fudge
import some
class SomeTest(unittest.TestCase):
@fudge.patch("mdle.Klaas")
def test_somethingb(self, Klaas_mock):
klaas_inst = (Klaas_mock.expects_call()
.returns_fake())
# Receiving the exception
some.instantiate()
Should I patch in a different way? Is this a limitation of Fudge, or a bug?
You have to patch the name where the object is being referenced, not where it's being defined.
Remember modules are just objects with a dict of names pointing to other objects (a class is an object too). The same object can have multiple (possibly identical) names in different modules. Patching makes a name temporarily point to a
Fake
rather than to the original object.I assume in your first (not working)
some.py
module you meant:That creates a name
some.Klass
that gets used in that module. The name happens to match the name inmdle
by default, but you actually have two names pointing to the same class object. It's the name insome
you need to patch if you want to use a fake instead, because that's the name used to reference the class in the module under test.Your test patches
mdle.Klass
which is not the name used insome
, so your code still picks up the real class object using its own unpatched name. You need to patchsome.Klass
instead in this case.In your second (working)
some.py
you import the wholemdle
module and reference the class using the name in that module. That's why patchingmdle.Klass
works in that case, you're patching the name that's being used.