Testing with unittest

Python 3.14 · ✓ verified by execution on 2026-07-27

Testing with unittest

When writing software, how do you prove your code actually works? You test it! Python provides a built-in framework called unittest that helps you write structured, automated tests for your code.

A test case is created by subclassing unittest.TestCase. Inside this class, any method that starts with the prefix test will automatically be recognized and run by the test runner.

python
import unittest

class TestDiscovery(unittest.TestCase):
    def helper_method(self):
        return True
    def test_thing(self):
        self.assertTrue(self.helper_method())

t = TestDiscovery('test_thing')
t.test_thing()
print('Passed!')
Output
Passed!

The Crux of Testing: Assertions

The core of every test is verifying that a certain condition holds true. The crux of each test is a call to assertEqual() to check for an expected result; assertTrue() or assertFalse() to verify a condition.

python
import unittest

class TestLogic(unittest.TestCase):
    def test_bools(self):
        self.assertTrue(10 > 5)
        self.assertFalse(10 < 5)

test = TestLogic('test_bools')
test.test_bools()
print('Passed!')
Output
Passed!

You might wonder why we don’t just use Python’s built-in assert statement. These methods are used instead of the assert statement so the test runner can accumulate all test results and produce a report.

python
import unittest

class TestAssert(unittest.TestCase):
    def test_fail(self):
        self.assertEqual(1, 2)

try:
    TestAssert('test_fail').test_fail()
except AssertionError as e:
    print(f'AssertionError: {e}')
Output
AssertionError: 1 != 2

The Testing Flow: Arrange, Act, Assert

A well-structured test follows three phases: Arrange the initial state, Act on the function you’re testing, and Assert the result.

Arrange Act Assert
The testing lifecycle flows linearly for each individual test.

To help with the Arrange phase, the setUp() method allows you to define instructions that will be executed before each test method, giving you a fresh slate for every test.

python
import unittest

class TestSetup(unittest.TestCase):
    def setUp(self):
        self.value = 42
    def test_value(self):
        self.assertEqual(self.value, 42)

t = TestSetup('test_value')
t.setUp()
t.test_value()
print('Setup and Test passed!')
Output
Setup and Test passed!

Testing Exceptions

Sometimes you expect your code to fail (for example, raising an error on bad input). You can use assertRaises() to verify that a specific exception gets raised.

python
import unittest

class TestErrors(unittest.TestCase):
    def test_division(self):
        with self.assertRaises(ZeroDivisionError):
            result = 1 / 0

test = TestErrors('test_division')
test.test_division()
print('Passed!')
Output
Passed!

Edge Cases

Be careful when testing floating-point numbers! Due to precision errors, 0.1 + 0.2 isn’t exactly 0.3. Instead of assertEqual, use assertAlmostEqual.

python
import unittest
class TestFloats(unittest.TestCase):
    def test_floats(self):
        # 0.1 + 0.2 is 0.30000000000000004
        self.assertAlmostEqual(0.1 + 0.2, 0.3)
t = TestFloats('test_floats')
t.test_floats()
print('Passed!')
Output
Passed!

Similarly, if you want to verify that two variables point to the exact same object in memory, use assertIs.

python
import unittest
class TestIdentity(unittest.TestCase):
    def test_is(self):
        a = [1, 2, 3]
        b = a
        self.assertIs(a, b)
        # c has the same values, but is a different object
        c = [1, 2, 3]
        self.assertIsNot(a, c)
t = TestIdentity('test_is')
t.test_is()
print('Passed!')
Output
Passed!

Check yourself

Which method is commonly used to verify that two values are exactly the same in `unittest`?

Reveal answer

self.assertEqual() — `assertEqual` checks for value equality. While `assertIs` checks for identity, it's not for general equivalence.

How does the `unittest` framework automatically discover which methods to run as tests?

Reveal answer

It looks for methods that begin with the prefix `test`. — Only methods that start with the prefix `test` are discovered and run automatically.

When does the `setUp()` method execute?

Reveal answer

Before every individual test method in the class. — `setUp()` runs before EACH test method to ensure a clean state.

Why should you use `unittest` methods like `assertEqual` instead of the built-in `assert` statement?

Reveal answer

They provide better error messages and let the test runner accumulate all results without crashing immediately. — Using `TestCase` methods allows the runner to report on all tests rather than aborting at the first failure, and it gives detailed diffs.

Challenges

Challenge 1 +50 XP

Fix the test method so that it correctly asserts that `calculate_total(10, 5)` equals `15` using the `unittest` methods.

python
  • Test 1 — expects "Passed!\n"
Show solution (0 XP)
import unittest

def calculate_total(a, b):
    return a + b

class TestMath(unittest.TestCase):
    def test_total(self):
        self.assertEqual(calculate_total(10, 5), 15)

t = TestMath('test_total')
t.test_total()
print('Passed!')

Challenge 2 +50 XP

The test runner is skipping this method! Rename the method so that the `unittest` framework recognizes it as a test.

python
  • Test 1 — expects "Passed!\n"
Show solution (0 XP)
import unittest

class TestLogic(unittest.TestCase):
    def test_logic(self):
        self.assertTrue(True)

t = TestLogic('test_logic')
t.test_logic()
print('Passed!')