Python is very specific language which gives developer huge flexibility.
So if I have class like this:
class Car:
def __init__(self, engine: Engine):
self._engine = engine # dependency injection
self.speed = 0
def accelerate(self, target_speed: int):
if self._engine.can_accelerate_to_speed(target_speed):
self.speed = target_speed
testing it is a piece of cake.
def test_car_acceleration():
car = Car(engine=MagicMock())
car.accelerate(100)
assert car.speed == 100
But what if the engine dependency is hidden?
class SlowCar:
def __init__(self):
self.engine = DefaultEngine() # hidden dependency or maybe implementation detail?
self.speed = 0
def accelerate(self, target_speed: int):
if self.engine.can_accelerate_to_speed(target_speed):
self.speed = target_speed
What is the right approach for the SlowCar? Let's assume SlowCar is intended to have DefaultEngine mounted by default, but nothing prevents class consumer from doing so:
car = SlowCar()
car.engine = HEMI()
Anyway should I treat SlowCar.engine as dependency or implementation detail?
Should I patch it out?
def test_slow_car():
with patch('path.to.SlowCar.DefaultEngine'):
car = SlowCar()
car.accelerate(100)
assert car.speed == 100
def test_slow_car_way2():
car = SlowCar()
car.engine = MagicMock()
car.accelerate(100)
assert car.speed == 100
I guess that while SlowCar.engine is "public" field I may consider patching it as it's part of public API so it seems to be clearly a dependency.
But if I would have SlowCar._engine.. A "private" field is not part of public API so it seems more like implementation detail and it should not be mocked/patched. That's internal part of SlowCar which I as a consumer should not care about, right? It's tightly coupled to SlowCar and SlowCar does work with it or does not work at all.