Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Logging and Monitoring Programs Professional Debugging Workflows

Assertions and Defensive Programming Unit Testing with Pytest

Testing and Debugging Business Applications

(a.k.a. “How to Break Your Own Code Before the Customer Does”)

Congratulations — your ML program runs! Now it’s time for the real question:

“Will it still run tomorrow? On someone else’s computer? With real data?”

This chapter is where you become not just a coder, but a code detective 🕵️ — armed with pytest, logging, and a lot of caffeine. ☕


🧩 1. The Harsh Truth About Business Apps

In the business world, “it works” means absolutely nothing. Your model could predict stock prices correctly 95% of the time — but if it crashes during quarterly reporting, guess who’s getting the 2 a.m. Slack message? You. 🫠

Testing and debugging keep your application from turning into a “Friday afternoon deployment horror story.”


🧪 2. Testing: How to Catch Bugs Before They Catch You

Think of testing like a vaccine for your code — small, controlled failures to prevent catastrophic ones later.

🔹 Unit Testing

Tests the smallest building blocks — functions, classes, or modules.

Example (with pytest):

## test_discount_calculator.py
from discount_calculator import calculate_discount

def test_calculate_discount():
    assert calculate_discount(100, 0.1) == 90

Unit tests are like tiny bodyguards for your logic — they punch bugs in the face before they get inside.

Pro tip: Test edge cases, not just happy paths. If you only test when everything goes right, your app will collapse faster than a cheap IKEA shelf.


🔹 Integration Testing

Tests how your modules work together — because even if each one is perfect alone, they might fight when connected. ⚔️

def test_end_to_end_data_pipeline():
    data = load_data("sales.csv")
    transformed = clean_data(data)
    model = train_model(transformed)
    assert model.is_trained

Integration tests are like couple’s therapy for your code — making sure everyone gets along under stress.


🔹 Regression Testing

Business changes. Models get updated. Suddenly your new version makes negative revenue predictions. 😬

Regression tests ensure your new features didn’t break the old ones. (Like a “don’t embarrass me in front of the client” check.)


🔹 Automated Testing Pipelines

Tie it all together with CI/CD pipelines — because running tests manually is so 2010.

Example GitHub Action snippet:

- name: Run Unit Tests
  run: pytest --maxfail=1 --disable-warnings -q

If tests fail, your code doesn’t deploy. Yes, it’s strict — but so is gravity.


🐛 3. Debugging: Turning “Why?” Into “Ah, There It Is.”

Debugging isn’t a skill; it’s a lifestyle. It’s 40% logic, 60% emotional resilience.

Let’s break down the modern debugging toolkit:

🔹 Logging Like a Pro

Don’t print your way out of problems. Use the logging module — it’s the adult version of print().

import logging

logging.basicConfig(level=logging.INFO)
logging.info("Model training started")
logging.warning("Missing values detected in column 'price'")
logging.error("Model crashed because 'price' was a string")

Rule of thumb: If your log file looks like a bad breakup text thread, you’re doing it right. 💔📜


🔹 The Art of Reproducing Bugs

You can’t fix what you can’t repeat.

  • Use seed control (np.random.seed(42)) for reproducible randomness.

  • Snapshot data versions with DVC or MLflow.

  • Log every environment variable that could betray you.

Debugging random bugs is like chasing a ghost that only appears when your manager walks in. 👻


🔹 The Power of the Debugger

Don’t underestimate IDE debuggers (like VS Code, PyCharm, or Jupyter’s %debug).

Set breakpoints, inspect variables mid-run, and say things like:

“Hmm, that list shouldn’t be empty…” until you achieve enlightenment. 🧘‍♂️


🔹 Mocking External Services

Your API shouldn’t actually hit a live payment system during tests. Use mocking to simulate external dependencies.

from unittest.mock import patch

@patch("payment_gateway.process_payment")
def test_checkout(mock_payment):
    mock_payment.return_value = True
    result = checkout(user="Alice", amount=50)
    assert result == "Success"

Mocking is pretending your system has friends, when really it’s testing alone in its room. 🤖


🧠 4. Testing Data and Models

Business apps aren’t just about code — your data can betray you too. Add data validation checks to your pipeline.

assert df["revenue"].notnull().all(), "Missing revenue values!"
assert (df["price"] > 0).all(), "Negative prices detected!"

Then, test your models for:

  • Output range sanity (e.g., probabilities ∈ [0, 1])

  • Drift detection (when today’s input looks nothing like last month’s)

  • Bias testing (especially if your model makes business-critical decisions)

Your model isn’t wrong — it’s just “creatively confident.” 🎨


💻 5. Debugging Production

Production bugs are special. They don’t appear when you look for them. They only happen at 3 a.m., during a live demo, or right after the boss says,

“Looks stable now.” 😬

Survival Kit:

  • Enable structured logging (JSON logs, timestamps, request IDs)

  • Add exception alerts (via Slack, Datadog, Sentry)

  • Use feature flags — turn off faulty features without redeploying

  • Maintain a staging environment that mirrors production

If you’re debugging in production, congratulations — you’re now a full-stack firefighter. 🔥


⚖️ 6. When to Stop Debugging

Sometimes the problem isn’t your code — it’s the assumptions. When debugging takes more time than rewriting, walk away, breathe, and refactor.

Debugging burnout is real. Remember:

“A 3-hour bug fix is just a 5-line rewrite in disguise.” ✨


🏁 7. Final Thoughts: Test, Don’t Hope

Testing and debugging aren’t chores — they’re insurance policies for your sanity.

Golden rules:

  • Test before you trust 🧪

  • Log before you cry 📜

  • Automate before you burn out 🤖

  • Never say “it worked yesterday” again 🙃


“Good testing prevents bad surprises. Bad testing gives you character development.”


# Your code here

Exercises

Exercise