unittestUnit 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
pdbDebugging 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)