Python ships its own testing framework built in — unittest — so a first real test needs no extra package at all. (pytest, mentioned in this site's Where to Go Next lesson, is a popular third-party alternative with a lighter syntax, worth exploring once the underlying ideas are comfortable.)
# test_math.py
import unittest
def add(a, b):
return a + b
class TestAdd(unittest.TestCase):
def test_sums_two_numbers(self):
self.assertEqual(add(2, 3), 5)
if __name__ == '__main__':
unittest.main()python -m unittest test_math.py
# .
# ----------------------------------------------------------------------
# Ran 1 test in 0.000s
# OK| Method | Checks |
|---|---|
| assertEqual(a, b) | a == b |
| assertNotEqual(a, b) | a != b |
| assertTrue(x) | x is truthy |
| assertIsNone(x) | x is None |
| assertRaises(ExceptionType) | A block of code raises the given exception |
| assertIn(item, container) | item is found inside container |
def divide(a, b):
if b == 0:
raise ValueError('Cannot divide by zero')
return a / b
class TestDivide(unittest.TestCase):
def test_raises_on_zero(self):
with self.assertRaises(ValueError):
divide(10, 0)Run automatically before and after every test method in a class — useful for repeated preparation, like creating a fresh object each time.
class TestShoppingCart(unittest.TestCase):
def setUp(self):
self.cart = ShoppingCart() # a fresh cart before every test
def test_starts_empty(self):
self.assertEqual(len(self.cart.items), 0)
def test_add_item(self):
self.cart.add('apple')
self.assertIn('apple', self.cart.items)python -m unittest discover
# Finds and runs every file matching test_*.py automaticallyTest the failure cases too
A test suite that only exercises the "happy path" (valid input, expected success) misses most real bugs — deliberately write at least one test for bad input, an edge case (an empty list, a zero), or an expected exception.