Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing Private Methods in Python: Unit Test or Functional Test?

After reading about testing private methods in Python, specifically referring to this accepted answer, it appears that it is best to just test the public interface. However, my class looks like this:

class MyClass:

  def __init__(self):
    # init code

  def run(self):
    self.__A()
    self.__B()
    self.__C()
    self.__D()

  def __A(self):
    # code for __A

  def __B(self):
    # code for __B

  def __C(self):
    # code for __C

  def __D(self):
    # code for __D

Essentially, I created a class to process some input data through a pipeline of functions. In this case, it would be helpful to test each private function in turn, without exposing them as public functions. How does one go about this, if a unit test can't execute the private function?

like image 340
darksky Avatar asked Mar 16 '13 18:03

darksky


1 Answers

Python does some name mangling when it puts the actually-executed code together. Thus, if you have a private method __A on MyClass, you would need to run it like so in your unit test:

from unittest import TestCase

class TestMyClass(TestCase):
    def test_private(self):
        expected = 'myexpectedresult'
        m = MyClass()
        actual = m._MyClass__A
        self.assertEqual(expected, actual)

The question came up about so-called 'protected' values that are demarcated by a single underscore. These method names are not mangled, and that can be shown simply enough:

from unittest import TestCase

class A:

    def __a(self):
        return "myexpectedresult"

    def _b(self):
        return "a different result"


class TestMyClass(TestCase):

    def test_private(self):
        expected = "myexpectedresult"
        m = A()
        actual = m._A__a()
        self.assertEqual(expected, actual)

    def test_protected(self):
        expected = "a different result"
        m = A()
        actual = m._b()
        self.assertEqual(expected, actual)
        # actual = m._A__b() # Fails
        # actual = m._A_b()  # Fails
like image 182
Nathaniel Ford Avatar answered Oct 05 '22 19:10

Nathaniel Ford