Professional developers write tests — code that checks that other code works correctly. Tests catch bugs before they reach users, make refactoring safer, and serve as living documentation of what your code is supposed to do.
Key Concepts
Why Test?
Manual testing is slow and forgetful. Automated tests run in seconds and catch regressions — bugs introduced when you change existing code. Tests give you confidence to make changes.
unittest Module
import unittest class TestMyFunction(unittest.TestCase): def test_basic(self): self.assertEqual(add(2, 3), 5) def test_negative(self): self.assertEqual(add(-1, 1), 0) if __name__ == '__main__': unittest.main()
Common Assertions
assertEqual(a, b) — a == b assertNotEqual(a, b) — a != b assertTrue(x) — x is truthy assertRaises(Error, func, args) — func raises Error assertIn(item, collection) — item in collection
pytest (Popular Alternative)
pytest is simpler: just write functions starting with test_: def test_add(): assert add(2, 3) == 5 Run with: pytest tests/ pytest auto-discovers tests and gives clear output.
import unittest
# Functions to test
def celsius_to_fahrenheit(c):
return c * 9/5 + 32
def is_palindrome(s):
s = s.lower().replace(" ", "")
return s == s[::-1]
def clamp(value, min_val, max_val):
"""Clamp value between min and max"""
if min_val > max_val:
raise ValueError("min must be <= max")
return max(min_val, min(max_val, value))
# Test suite
class TestFunctions(unittest.TestCase):
def test_boiling_point(self):
self.assertAlmostEqual(celsius_to_fahrenheit(100), 212.0)
def test_freezing_point(self):
self.assertAlmostEqual(celsius_to_fahrenheit(0), 32.0)
def test_palindrome_true(self):
self.assertTrue(is_palindrome("racecar"))
self.assertTrue(is_palindrome("A man a plan a canal Panama"))
def test_palindrome_false(self):
self.assertFalse(is_palindrome("hello"))
def test_clamp_middle(self):
self.assertEqual(clamp(5, 0, 10), 5)
def test_clamp_below(self):
self.assertEqual(clamp(-5, 0, 10), 0)
def test_clamp_invalid(self):
with self.assertRaises(ValueError):
clamp(5, 10, 0)
# Run tests
loader = unittest.TestLoader()
suite = loader.loadTestsFromTestCase(TestFunctions)
runner = unittest.TextTestRunner(verbosity=2)
result = runner.run(suite)
print(f"\nTests run: {result.testsRun} Failures: {len(result.failures)} Errors: {len(result.errors)}")