I have this class
class Waterfall: def height_in_feet(self): return requests.get("https://nicaragua.waterfall.com/height").content
It's making web service calls to Nicaragua all the time, requiring me to be online whenever I run my tests:
import unittest class ExploringMocking(unittest.TestCase): def test_using_the_real_class(self): waterfall = Waterfall() assert waterfall.height_in_feet() == 164
For this reason, I'd like to mock the
Waterfall class (as it has so
many methods and I want the method signatures to all be correct, I use
unittest.mock.create_autospec) and provide my own implementation of
import types import unittest.mock class ExploringMocking(unittest.TestCase): def test_mocking_a_class(self): waterfall = unittest.mock.create_autospec(Waterfall) waterfall.height_in_feet = types.MethodType( self.my_height_func, self ) assert waterfall.height_in_feet() == 10 def my_height_func(self, ref): return 10
The essential bit here is the
types.MethodType which is what you
need to do when overriding the method on a class instance. Just
waterfall.hight_in_feet = self.my_height_func will not cut it.
With this in place, I can implement any logic I want in
my_height_func which will get executed whenever
Waterfall#height_in_feet() would have been.
If you strive to see the point of this, consider the case where you
have a method that uses an instance
Waterfall. When passing in an
Waterfall, we want to control what the method is
returning depending on the input. Imagine that we have this silly
def get_colour_of_waterfall(waterfall: Waterfall) -> str: if waterfall.height_in_feet() > 10: return "blue" else: return "true"
By using the original implementation of
Waterfall, we not only have
to be online all the time (and thus writing an integration test instead
of a unit test), but even more importantly, we cannot test what this
get_colour_of_waterfall method returns given different situations
and return values from the Nicaragua web service.
Waterfall#height_in_feet() method solves both of
these problems. With it, we not only can write a pure unit test (no
need to interact with the other system, no need to be online) and we
can easily simulate different values, or exceptions, returned from