Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

How can I use unittest cleanup to prevent one test affecting another?

Quick answer

Before changing shared or temporary state in a unittest, save its current value and register a function that restores it with self.addCleanup(...). The registered cleanup runs after tearDown() and still runs if setUp() fails; cleanups run in last-in, first-out order. Register restoration as soon as you have captured the old state, so the test does not depend on reaching its final line to undo the change. [S1]

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

I have a test that changes a module-level setting, and sometimes a later test behaves differently. What is the basic cleanup pattern?

Geez

Save the old value, register a restoration callback, then make the temporary change. For example:

import unittest

FEATURE_ENABLED = False

def set_feature_enabled(value):
    global FEATURE_ENABLED
    FEATURE_ENABLED = value

class FeatureTests(unittest.TestCase):
    def test_enabled_feature(self):
        old_value = FEATURE_ENABLED
        self.addCleanup(set_feature_enabled, old_value)
        set_feature_enabled(True)
        self.assertTrue(FEATURE_ENABLED)

The order matters: capture the original value, register how to restore it, then change it. The callback receives the saved value, so it restores the state that was present before the test rather than assuming a default. Registered cleanups run after tearDown() and in last-in, first-out order. [S1]

Follow-up question

Why use addCleanup instead of putting the restoration at the end of the test?

Geez

Restoration at the end of the test body depends on the test reaching that line. If an assertion or another operation fails first, the restoration code may not run. A cleanup registered before the change gives unittest a callback to run without relying on the test reaching its final line. [S1]

Use a callback that actually restores the state you changed. In this example, set_feature_enabled updates the module-level variable; a callback that changes an unrelated test-case attribute would not restore it. If the state belongs to an object or setting with a different restoration method, pass the appropriate function and saved value to addCleanup.

Follow-up question

Can you show how I would register cleanup when the temporary change happens in setUp?

Geez

Capture and register the restoration in setUp() before changing the setting. Then the cleanup is registered even if a later setup step fails:

import unittest

FEATURE_ENABLED = False

def set_feature_enabled(value):
    global FEATURE_ENABLED
    FEATURE_ENABLED = value

class FeatureTests(unittest.TestCase):
    def setUp(self):
        old_value = FEATURE_ENABLED
        self.addCleanup(set_feature_enabled, old_value)
        set_feature_enabled(True)
        # Other setup may follow.

    def test_feature_is_enabled(self):
        self.assertTrue(FEATURE_ENABLED)

Here, the variable starts as False and setup temporarily sets it to True. The cleanup receives the saved value, so it can restore the value that was present when setup began. Registered cleanups still run if setUp() fails, even though tearDown() is not called. [S1] That is why the cleanup should be registered before any later setup operation that might fail.

Follow-up question

What should I check if I am cleaning up several changes, or if a later test still sees altered state?

Geez

Check that every callback restores the actual state its test changed, using the value captured before the change rather than a guessed default. If a test changes several independent settings, capture and register restoration for each one before changing it. Cleanups run in last-in, first-out order, so the most recently registered callback runs first. [S1] Consider whether that reverse order matches how your changes should be undone.

If a later test still sees altered state, inspect the sequence: Was cleanup registered before the change? Does the callback target the same variable or object? Does it restore the saved value? Also check whether another test changes that state without registering its own cleanup. addCleanup runs the callback you provide; it does not automatically undo unrelated or unregistered side effects.

A practical checklist

  • Identify the exact shared or temporary state the test changes.

  • Capture its current value before changing it.

  • Register a callback with self.addCleanup immediately after capturing the value.

  • Make the temporary change only after restoration is registered.

  • For changes in setUp(), register cleanup there before later setup work can fail.

  • For multiple changes, check that each callback restores its intended state and account for last-in, first-out order.

A few more useful answers

Does addCleanup run before or after tearDown?

Registered cleanups run after tearDown(). They run in last-in, first-out order. [S1]

Will a cleanup registered in setUp run if setUp fails?

Yes. Registered cleanups still run if setUp() fails, even though tearDown() is not called. Register the cleanup before the setup operation that might fail. [S1]

Does addCleanup automatically restore every change a test makes?

No. It runs the callback you register; that callback must explicitly restore the state or effect you want undone.

Sources

References used for this guide.

  1. [S1] unittest — Unit testing framework (Python 3.15 documentation)
    docs.python.org · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work