Lab 13: Debugging & Testing

🎯 Objective

Debug Python programs systematically using print statements, assertions, logging, and pdb — then write unit tests with unittest and pytest to prevent regressions.

📚 Background

Bugs are inevitable. The difference between junior and senior developers is how quickly and systematically they find them. Python offers a full debugging toolkit: print() for quick checks, assert for invariants, the logging module for production-grade diagnostics, and pdb for step-by-step debugging. pytest and unittest provide automated testing so bugs you fix don't come back.

⏱️ Estimated Time

35 minutes

📋 Prerequisites

  • Lab 12: OOP Basics

🛠️ Tools Used

  • Python 3.12

  • pytest

🔬 Lab Instructions

Step 1: Strategic Print Debugging

📸 Verified Output:

Step 2: Assertions for Invariants

📸 Verified Output:

Step 3: The logging Module

📸 Verified Output:

💡 Log levels (lowest to highest): DEBUG → INFO → WARNING → ERROR → CRITICAL. Production systems typically use INFO; development uses DEBUG. Never use print() in production code — logging can be redirected to files, databases, or monitoring services.

Step 4: Writing Unit Tests with unittest

📸 Verified Output:

Step 5: pytest Style Testing

📸 Verified Output:

Step 6: Test-Driven Development (TDD)

📸 Verified Output:

Step 7: Debugging with traceback

📸 Verified Output:

Step 8: Common Bug Patterns and Fixes

📸 Verified Output:

✅ Verification

Expected output:

🚨 Common Mistakes

  1. Bare except: swallows bugs: Always catch specific exceptions; log them.

  2. Assertions in production: python -O (optimize) strips assertions — don't use them for validation.

  3. Over-asserting: Every function doesn't need assertions — focus on public API entry points.

  4. Not running tests frequently: Tests catch regressions only if you run them. Use CI.

  5. Testing implementation, not behavior: Test what the function does, not how it does it.

📝 Summary

  • Print debugging: add print(f"DEBUG: {var=}") (Python 3.8+ = in f-string shows name AND value)

  • assert condition, "message" — document and enforce invariants (not for user validation)

  • logging module: DEBUG/INFO/WARNING/ERROR/CRITICAL — use instead of print in real code

  • unittest.TestCase — class-based tests with assertEqual, assertRaises, subTest

  • pytest — simpler syntax, powerful features: parametrize, fixtures, approx

  • TDD: Write test → Watch it fail → Implement → Watch it pass → Refactor

🔗 Further Reading

Last updated