I have a model in django that has a foreign key to another model, and during unit testing I want to avoid tight-coupling of the two models and create a stub for the other model that will return different values each time.
Contrived example:
class Moon(models.Model):
def phase(self):
# some extremely complex code
class Wolf(models.Model):
moon = models.ForeignKey(Moon)
mood = models.CharField()
def update_mood(self):
if (self.moon.phase == 'new moon'):
self.mood = "good"
if (self.moon.phase == 'waxing crescent'):
self.mood = "hopefull"
...
Example for the above:
w = Wolf()
m = Moon()
# m.phase = 'new moon'
w.moon = m
w.update_mood()
w.mood # 'good'
Now I want to test the Wolf().moon property after I do an update_mood() call, without actually touching the Moon model at all - b开发者_JAVA技巧ecause its a very complex model that goes out into all kinds of external systems to figure out its phase.
Usually I would use monkey-patching for this, but since .mood is a property ... I can't really assign to it in a monkey-patching way.
Help.
With a bit of digging, stumbled on the model add_to_class() method that does proper monkey patching and can override foreign key properties on a model.
Example of usage:
class FakeMoon(object):
def get_phase(self): return self._phase
def set_phase(self, phase): self._phase = phase
phase = property(get_phase, set_phase)
# this bit is the answer to the question above
Wolf.add_to_class("moon", FakeMoon())
w = Wolf()
w.moon.phase = 'new moon'
w.update_mood()
assert w.mood == 'good'
w.moon.phase = 'waxing crescent'
w.update_mood()
assert w.mood == 'hopefull'
For the sake of testing, you could override (monkey patch, if you want to use it in test environment only) __ getattribute__.
In __ getattribute__ check if the property moon is called, return the value or set the value in a temporary var.
精彩评论