unittest
Unit testing involves testing individual components (functions, methods, classes) to ensure they work correctly. Python's built-in unittest
module provides tools for:
# calculator.py (Module to test) def add(a, b): return a + b def subtract(a, b): return a - b def multiply(a, b): return a * b def divide(a, b): if b == 0: raise ValueError("Cannot divide by zero!") return a / b
# test_calculator.py (Test file) import unittest from calculator import add, subtract, multiply, divide class TestCalculator(unittest.TestCase): def test_add(self): self.assertEqual(add(2, 3), 5) # 2 + 3 = 5 self.assertEqual(add(-1, 1), 0) # -1 + 1 = 0 def test_subtract(self): self.assertEqual(subtract(5, 3), 2) # 5 - 3 = 2 self.assertEqual(subtract(10, -5), 15) # 10 - (-5) = 15 def test_multiply(self): self.assertEqual(multiply(3, 4), 12) # 3 * 4 = 12 self.assertEqual(multiply(-2, 5), -10) # -2 * 5 = -10 def test_divide(self): self.assertEqual(divide(10, 2), 5) # 10 / 2 = 5 self.assertAlmostEqual(divide(1, 3), 0.333, places=3) # Approximate float comparison # Test exception handling with self.assertRaises(ValueError): divide(10, 0) # Should raise ValueError if __name__ == "__main__": unittest.main()
python -m unittest test_calculator.py
TDD follows this cycle:
factorial
function# Step 1: Write the test first def test_factorial(self): self.assertEqual(factorial(0), 1) self.assertEqual(factorial(5), 120)
# Step 2: Implement the function def factorial(n): if n == 0: return 1 return n * factorial(n - 1)
# Step 3: Run the test python -m unittest test_factorial.py
pdb
Debugging is the process of finding and fixing errors in code. Python provides:
pdb
(Python Debugger): Interactive debugging toolpdb
# buggy_script.py def divide_numbers(a, b): result = a / b # Potential ZeroDivisionError return result def main(): x = 10 y = 0 print(divide_numbers(x, y)) if __name__ == "__main__": import pdb; pdb.set_trace() # Start debugger main()
python buggy_script.py
pdb
commands:Logging helps track program execution by recording messages (debug, info, warnings, errors).
logging
import logging # Configure logging logging.basicConfig( level=logging.DEBUG, # Minimum level to log format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", filename="app.log" # Log to file ) def divide(a, b): logging.debug(f"Attempting division: {a} / {b}") try: result = a / b logging.info(f"Division successful: {result}") return result except ZeroDivisionError: logging.error("Division by zero!") raise divide(10, 2) divide(5, 0)
app.log
)Profiling measures code performance (execution time, memory usage).
cProfile
# slow_function.py import time def slow_function(): total = 0 for i in range(1000000): total += i return total if __name__ == "__main__": import cProfile cProfile.run("slow_function()")
python slow_function.py
Topic | Key Tools | Use Case |
---|---|---|
Unit Testing | unittest , pytest | Verify individual functions |
Debugging | pdb , breakpoint() | Step-through code execution |
Logging | logging module | Track runtime events |
Profiling | cProfile , timeit | Measure performance |
pdb
for interactive debuggingDEBUG
, INFO
, ERROR
)