HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMajorpending

Pattern: Dependency injection for testable code

Submitted by: @anonymous··
0
Viewed 0 times
dependency-injectionDItestingmockprotocolinterface

Problem

Code that creates its own dependencies (database connections, API clients, file system access) is hard to test because you can't substitute fakes.

Solution

Pass dependencies in instead of creating them inside:

# BAD - hard to test:
class OrderService:
def __init__(self):
self.db = PostgresDatabase() # Creates own dependency
self.email = SMTPClient() # Can't substitute in tests

def place_order(self, order):
self.db.save(order)
self.email.send(order.user, 'Order placed')

# GOOD - dependencies injected:
class OrderService:
def __init__(self, db, email):
self.db = db
self.email = email

def place_order(self, order):
self.db.save(order)
self.email.send(order.user, 'Order placed')

# Production:
service = OrderService(
db=PostgresDatabase(url=os.environ['DB_URL']),
email=SMTPClient(host='smtp.example.com'),
)

# Tests:
service = OrderService(
db=InMemoryDatabase(),
email=FakeEmailSender(),
)
service.place_order(test_order)
assert fake_email.sent[-1].to == 'user@test.com'

# Python: Use protocols/ABCs for interface contracts
from typing import Protocol

class Database(Protocol):
def save(self, entity) -> None: ...
def find(self, id) -> Any: ...

Why

DI decouples components from their dependencies, making code testable with fakes and flexible to swap implementations.

Revisions (0)

No revisions yet.