Dependency isolation strategies
Overview
**Memorizable line:** Dependency isolation means separating your core logic from outside services. When your code directly calls a database or an API, it is hard to test. We call these outside services `dependencies`. If the database is down, your test fails even if your logic is correct. Here is a function that checks if a student passed. It gets marks directly from a database. ```python def check_pass(student_id): # Direct dependency on an external database marks = db.get_marks(student_id) return marks > 40 ``` We isolate the dependency by passing the marks into the function instead. This is called Dependency Injection. ```python def check_pass(marks): # Now it does not depend on a database return marks > 40 ``` **Analogy:** Think of a chef making tea. If the chef goes to the farm to milk the cow, that is a hard dependency. If someone hands the chef a bottle of milk, that is isolation.
It makes your code easy to test. You can pass simple inputs instead of setting up a whole database.
Where used: pytest, FastAPI
Why learn this
- Allows you to write clean tests without needing real databases or APIs.
Code walkthrough
def process_payment(amount, charge_card):
if amount > 0:
return charge_card(amount)
return False
def fake_charge(amt):
return f'Charged {amt}'
print(process_payment(50, fake_charge))
Focus: return charge_card(amount)
Aha moment
def run_task(task_func):
return task_func()
def fake_task():
return 'Done'
print(run_task(fake_task))
Prediction: What does this print?
Common guess: It crashes because there is no real task.
Because we pass a fake function in, the code runs perfectly without needing a real task.
Common mistakes
- Hardcoding external calls: Putting API requests directly inside logic functions. Pass the data in instead.
Recall questions
- Explain dependency isolation in your own words, as if to a classmate.
- Why is it bad for a logic function to directly call a database?
Understanding checks
What prints, and why?
10.0
The `calculate_tax` function is isolated. It uses the `fake_get_rate` function passed into it.
Which function is easier to test? A: `def get_discount(): price = api.get_price(); return price * 0.9` or B: `def get_discount(price): return price * 0.9`
B
Function B takes the price as an argument. You do not need to fake the API to test it.
Practice tasks
Isolate a dependency
Given this working code, change it so that `send_sms` is passed in as a parameter to `notify_user`.
Challenge
Pass a fake dependency
Write a function `get_total(price, add_tax_func)`. It should return price plus the result of calling `add_tax_func(price)`.
Continue learning
Previous: Defining functions and return values