industryworker3595112
industryworker3595112

Reputation: 3759

How to test python module privates?

In python 2.7, is it possible to test module privates?

After running:

import unittest

__private_stuff = 1 # if it would have single underscore, it would not be a problem.

class ComplexTestCase(unittest.TestCase):
    def test_internal_symbol(self):
        self.assertEqual(__private_stuff, 1)

unittest.main(__name__)

Result is:

E
======================================================================
ERROR: test_internal_symbol (__main__.ComplexTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\files\y.py", line 7, in test_internal_symbol
    self.assertEqual(__private_stuff, 1)
NameError: global name '_ComplexTestCase__private_stuff' is not defined

----------------------------------------------------------------------


Is there any way arround it?
(without modifying the code to which I want to add tests)

Alternatives (that I would like to avoid)

One way would be to just rename the methods.
Other way would be to add additional renamed symbol private_stuff = __private_stuff.

But this becomes very tedious quickly.
Codebase uses these '__xyz' as public symbols (uses from other modules) and there is quite a lot of them.
Also there always exists '_xyz' and 'xyz' symbols.

(Trying to find the answer of "why", figured the only reasonable explanation
is that leading underscores was used to mark "modified" as in mathematical formulas "prime" is used. e.g. x and x' are similar, but not the same)

Upvotes: 0

Views: 410

Answers (2)

Dunes
Dunes

Reputation: 40778

There are a few ways you could prevent python invoking the name mangling algorithm in your class

Use getattr to retrieve the value of the attribute under test (as per 1.618's answer):

class ComplexTestCase(unittest.TestCase):
    def test_internal_symbol(self):
        private_stuff = getattr(module_under_test, '__private_stuff')
        self.assertEqual(private_stuff, 1)

Write the test method outside of a class:

def test_internal_symbol(self):
    self.assertEqual(module_under_test.__private_stuff, 1)

class ComplexTestCase(unittest.TestCase):
    test_internal_symbol = test_internal_symbol

Refactor the private attributes names to end with 3 underscores:

class ComplexTestCase(unittest.TestCase):
    def test_internal_symbol(self):
        self.assertEqual(module_under_test.__private_stuff___, 1)

Upvotes: 0

1.618
1.618

Reputation: 1765

Where is __private_stuff actually defined? Because I doubt it's defined in your test case module. If it really is, then this will work:

import unittest

__private_stuff = 1 # if it would have single underscore, it would bot be a problem.

class ComplexTestCase(unittest.TestCase):
    def test_internal_symbol(self):
        private_stuff = globals()['__private_stuff']
        self.assertEqual(private_stuff, 1)

unittest.main(__name__)

Otherwise, if it's in some other module, this should work, although I didn't test it:

import unittest
import other_module

__private_stuff = 1 # if it would have single underscore, it would bot be a problem.

class ComplexTestCase(unittest.TestCase):
    def test_internal_symbol(self):
        private_stuff = getattr(other_module, '__private_stuff')
        self.assertEqual(private_stuff, 1)

unittest.main(__name__)

Upvotes: 3

Related Questions