Excellent.
DAY 29 is about professional survivability — code that doesn’t just work today, but keeps working months later.

Most real-world failures are not logic bugs — they’re untested changes.


🧠 DAY 29 — Testing, Debugging & Maintainability

(Unit tests, mocking, debugging & long-term code health)


🔑 CORE IDEA OF DAY 29

Good code is testable code.
Untested code is broken code — it just hasn’t failed yet.

Testing is not a formality. It’s engineering insurance.


1️⃣ The Testing Pyramid (Mental Model)

Image
Image
Image
Image

From bottom to top:

  1. Unit tests (many, fast)
  2. Integration tests (fewer)
  3. End-to-end tests (very few, slow)

🧠 Most confidence comes from unit tests.


2️⃣ What Is a Unit Test (Precisely)

A unit test:

  • Tests one function or method
  • In isolation
  • With controlled inputs
  • Deterministic outcome

Example:

def add(a, b):
    return a + b

Test:

def test_add():
    assert add(2, 3) == 5

No I/O. No network. No randomness.


3️⃣ Why Tests Fail in Real Projects

Common reasons:

  • Code tightly coupled to I/O
  • Hidden global state
  • Side effects everywhere
  • No separation of concerns

🧠 Testability is a design property, not a testing problem.


4️⃣ Writing Testable Code (Design Rules)

✔ Separate logic from I/O
✔ Pass dependencies explicitly
✔ Avoid globals
✔ Use pure functions where possible

Bad:

def get_user():
    return db.query(...)

Good:

def get_user(db):
    return db.query(...)

This enables mocking.


5️⃣ Assertions: What to Test

Test:

  • Behavior
  • Outputs
  • State transitions

Avoid testing:

  • Implementation details
  • Private helper internals
  • Exact timing (unless required)

Rule:

Test what, not how.


6️⃣ Mocking (CRITICAL for Interviews)

Mocking replaces real dependencies with fake ones.

Why:

  • Network is slow
  • DB is external
  • File system is unpredictable

Conceptually:

def process(fetch):
    data = fetch()
    return data.upper()

Test:

def fake_fetch():
    return "hello"

assert process(fake_fetch) == "HELLO"

No real network call needed.


7️⃣ Mocking vs Faking vs Stubbing

TechniquePurpose
StubReturn fixed data
FakeSimplified implementation
MockAssert interactions

In interviews, “mock” often means any of the above.


8️⃣ Debugging Strategy (Senior-Level)

Don’t randomly print.

Step-by-step approach:

  1. Reproduce reliably
  2. Minimize the failing case
  3. Inspect assumptions
  4. Narrow scope
  5. Fix root cause
  6. Add a test

🧠 Every bug fixed without a test will return.


9️⃣ Debugging Tools (Mental Toolkit)

  • Tracebacks → where it broke
  • Stack frames → how it got there
  • Logging → what state looked like
  • Assertions → validate invariants

Avoid:

print("here")

Prefer:

assert x is not None

🔟 Logging vs Printing (IMPORTANT)

Printing:

  • For debugging locally
  • Not structured
  • Hard to filter

Logging:

  • Levels (DEBUG, INFO, ERROR)
  • Structured
  • Production-safe

Rule:

Print for learning, log for systems.


11️⃣ Common Testing Anti-Patterns 🚨

❌ Tests depend on order
❌ Tests share mutable state
❌ Tests hit real APIs
❌ Tests break on minor refactors
❌ No assertions (only prints)

Interviewers spot these instantly.


12️⃣ Regression Tests (Why Bugs Stay Dead)

When a bug is found:

  1. Write a test that fails
  2. Fix the bug
  3. Keep the test forever

This is how large systems remain stable.


🔥 INTERVIEW TRAPS (DAY 29)

Q1

Why is mocking important?

✔ Isolation
✔ Speed
✔ Determinism


Q2

Why tests shouldn’t depend on real DBs?

✔ Slow
✔ Flaky
✔ Hard to control


Q3

What’s the difference between testing and debugging?

✔ Testing prevents bugs
✔ Debugging finds bugs


🧠 DAY 29 MENTAL CHECKLIST

Before shipping code:

  1. Can this be tested?
  2. Are edge cases covered?
  3. Are failures deterministic?
  4. Is there a regression test?
  5. Will future changes break silently?

📝 DAY 29 ASSIGNMENT (MANDATORY)

1️⃣ Identify design flaw:

def get_data():
    import requests
    return requests.get("http://api").json()

Why is this hard to test?
How would you redesign it?


2️⃣ Explain clearly:

  • Difference between unit and integration tests
  • Why tests are part of design, not QA

3️⃣ Design question:

How would you test a function that retries on network failure?

(Hint: dependency injection + mocks)


🔜 DAY 30 PREVIEW (FINAL DAY 🔥)

DAY 30 — Python Internals Recap + Interview Mastery

You’ll:

  • Connect all concepts end-to-end
  • Review CPython execution model
  • Practice killer interview questions
  • Build a final mental model of Python

When ready, say 👉 “START DAY 30”