19

I need to write a test that will check a local variable value inside a static function. I went through all the unittest docs but found nothing yet.

4
  • Show us the static function you are going to test. Generally, local variable is local, so it is not supposed to be tested from outside. Anyway, you may add asserts and other testing stuff inside the function, but this is not something one could call unittest. Commented May 28, 2014 at 10:57
  • need to write a test that will check a local variable value inside a static function why? what value does that add? Commented May 28, 2014 at 11:15
  • Thank you. I realized that it was a quite bad idea at all. Commented May 30, 2014 at 11:16
  • Just for reference: if your function calls another one and that variable is one of its parameters, you can mock that second function and assert it's called with certain values. Check docs.python.org/3/library/unittest.mock.html Commented Oct 8, 2021 at 13:20

2 Answers 2

34

You can't. Local variables are local to the function and they cannot be accessed from the outside.

But the bigger point is that you shouldn't actually be trying to test the value of a local variable. Functions should be treated as black boxes from the outside. The are given some parameters and they return some values and/or change the external state. Those are the only things you should check for.

Sign up to request clarification or add additional context in comments.

2 Comments

Hey But code coverage shows local variables assignments as missing what for that ?
Code coverage doesn't care about the levels of abstraction that unit testing does. It's only concern is measuring what code gets used, not the correctness or behavior of that code.
0

I had to unit test by mocking a local variable which held a function, so doctest and unittest can both use these ways to mock/test a local variable, function or not:

"""Mocking a local function in doctest and unittest, by Cees Timmerman 2025-03-22.
Also checks a variable in a static function for https://stackoverflow.com/q/23909692/819417

>>> 'some_local_var_in_this_static_function = "hello"' in inspect.getsource(get_input)
True
"""

import inspect
import sys
import unittest
from typing import Callable


def get_input() -> str:
    """How static is assigning to a temp var? Very; immutable is different in this context.
    >>> _ = get_input()
    """
    some_local_var_in_this_static_function = "hello"

    # Static runtime integrity check.
    if some_local_var_in_this_static_function != "hello":
        raise ValueError("Runtime panic! The static function get_input is corrupt!")

    # Static test time integrity check.
    if "doctest.py" in str(sys.modules["__main__"].__file__) or "unittest" in str(sys.modules["__main__"].__file__):
        if some_local_var_in_this_static_function != "hello":
            raise ValueError(
                "Unit test fail! The static function get_input is corrupt!"
            )

    return input()


def way_a(x: Callable[[], str] = get_input) -> str:
    """
    >>> way_a(lambda: "42")
    '42'
    """
    return x()


def way_b() -> str:
    """
    >>> way_b()
    '42'
    """
    global get_input

    local_backup = get_input
    if "doctest.py" in str(sys.modules["__main__"].__file__):
        get_input = lambda: "42"
    rv = get_input()
    # Assume all the usage of variable get_input has been sufficiently mocked, so restore regular function for the rest of this program.
    get_input = local_backup
    return rv


class TestWays(unittest.TestCase):

    def test_way_a(self) -> None:
        self.assertEqual(way_a(lambda: "42"), "42")

    def test_way_b(self) -> None:
        global get_input
        get_input = lambda: "42"
        self.assertEqual(way_b(), "42")

    def test_local_function_var(self) -> None:
        self.assertTrue(
            'some_local_var_in_this_static_function = "hello"'
            in inspect.getsource(get_input)
        )

    def test_just_run_it(self) -> None:
        get_input()


if __name__ == "__main__":
    way_a()
    way_b()
>python test_doctest_mock.py                
a
a

>python -m doctest -v test_doctest_mock.py  
Trying:
    'some_local_var_in_this_static_function = "hello"' in inspect.getsource(get_input)
Expecting:
    True
ok
Trying:
    _ = get_input()
Expecting nothing
a
ok
Trying:
    way_a(lambda: "42")
Expecting:
    '42'
ok
Trying:
    way_b()
Expecting:
    '42'
ok
5 items had no tests:
    test_doctest_mock.TestWays
    test_doctest_mock.TestWays.test_just_run_it
    test_doctest_mock.TestWays.test_local_function_var
    test_doctest_mock.TestWays.test_way_a
    test_doctest_mock.TestWays.test_way_b
4 items passed all tests:
   1 tests in test_doctest_mock
   1 tests in test_doctest_mock.get_input
   1 tests in test_doctest_mock.way_a
   1 tests in test_doctest_mock.way_b
4 tests in 9 items.
4 passed and 0 failed.
Test passed.

>python -m unittest -v test_doctest_mock.py
test_just_run_it (test_doctest_mock.TestWays) ... a
ok
test_local_function_var (test_doctest_mock.TestWays) ... ok
test_way_a (test_doctest_mock.TestWays) ... ok
test_way_b (test_doctest_mock.TestWays) ... ok

----------------------------------------------------------------------
Ran 4 tests in 2.034s

OK

Local vars can be tested locally from a detect unit test if block demonstrated in way_b. If the code you're replacing is external, you can use the mock.patch decorator as shown here.

8 Comments

Try running this instead of doctesting it, and you'll get an UnboundLocalError in way_b.
I don't. Which version are you using? AI comment?
UnboundLocalError demo on 3.12, but the problem should reproduce on any Python version that supports the syntax involved.
Perhaps you named your file doctest.py, or something ending in doctest.py, inadvertently triggering the code path that was only supposed to run while doctesting. That would have hidden the error (and also made way_b use lambda: "42" instead of reading input).
Thanks. I must've tested when the way_a() line was duplicated. Fixed now.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.