Skip to main content

Introduction to unittest (Part 2): Assertions, test discovery, and running tests

Part 1 showed TestCase scaffolding. You now need richer assertions, lifecycle hooks, and predictable discovery so suites scale past a handful of files.


📚 Prerequisites

  • Basic unittest.TestCase examples.

🎯 What you'll learn

  • Choose specific assertion helpers for clearer failure output.
  • Control discovery flags (-k, -f, verbosity).
  • Use setUp / tearDown without entangling shared global state.

Assertion cookbook

MethodWhen to use
assertEqual(a, b)Value equality with helpful diffs
assertAlmostEqualFloating tolerances
assertRaises / assertRaisesRegexExpected errors
assertIsNone / assertIsNotNoneOptional returns
assertIn / assertCountEqualCollections membership
assertTrue / assertFalseLast resort—prefer concrete checks
import unittest

def divide(a: float, b: float) -> float:
if b == 0:
raise ValueError("b must be nonzero")
return a / b
class TestDivide(unittest.TestCase):
def test_zero_denominator(self):
with self.assertRaises(ValueError):
divide(10, 0)

Discovery tips

python -m unittest discover -s tests -p "test_*.py" -v

-s sets the start directory; -p tweaks the pattern when your organization standardizes naming; -v prints each test method for long CI logs.

Stop on first failure while iterating locally:

python -m unittest discover -f

Setup and teardown hooks

class TestTmp(unittest.TestCase):
def setUp(self):
self.fixture = {"count": 0}

def tearDown(self):
# release resources opened in setUp
self.fixture.clear()

Prefer fresh fixtures per test unless setUpClass’s expensive resource is immutable (read-only databases, compiled models).


💡 Key takeaways

  • Tests should read like specifications; verbose assertion methods double as documentation for future maintainers.

➡️ Next steps

Switch to pytest’s function style in Introduction to pytest (Part 1).