9

I have a class, which use a class variable to choose which logic to execute.

#in file1:

class SomeHelper():
    def __init__(self):
        self.my_var = 0

#in file2: 
import file1
class MyClass():
    ...
    ...
    def calculate():
        inst = file1.SomeHelper()
        if x > inst.my_var:
           etc etc

I am writing a unit test and mocking SomeHelper() in another file:

from file 2 import MyClass
# tried both
@patch('file2.file1') OR @patch('file2.file1.SomeHelper')
def test_calculate(self, mock_helper):
    mock_helper.my_var = 0
    to_test = MyClass.calculate()

And I get the following error:

TypeError: '>' not supported between instances of 'MagicMock' and 'int'.

I thought I defined my_var after I patched the module.

Lin Du
  • 88,126
  • 95
  • 281
  • 483
RebeccaK375
  • 871
  • 3
  • 17
  • 28
  • 1
    `mock_helper` is the whole of `file1`, you need to be working with `mock_helper.SomeHelper().my_var`. But note that the complexity of mocking this suggests that you need to apply other patterns, e.g. dependency inversion, to make the code easier to test. – jonrsharpe May 08 '18 at 22:12
  • Alas, I tried it and it did not work. – RebeccaK375 May 09 '18 at 14:15
  • Kidding - the parenthesis did it. Without (), it was mocking the class rather than instance of class. Thanks! If you post this as an answer, I will accept it. – RebeccaK375 May 09 '18 at 15:29

1 Answers1

2

Here is the unit test solution for Python 3.7.5:

file1.py:

class SomeHelper():
    def __init__(self):
        self.my_var = 0

file2.py:

import file1


class MyClass():
    @classmethod
    def calculate(cls):
        x = 1
        inst = file1.SomeHelper()
        if x > inst.my_var:
            return True
        return False

test_file2.py:

import unittest
from unittest.mock import patch
from file2 import MyClass


class TestMyClass(unittest.TestCase):
    @patch('file2.file1')
    def test_calculate(self, mock_file1):
        inst = mock_file1.SomeHelper.return_value
        inst.my_var = 0.5
        to_test = MyClass.calculate()
        self.assertTrue(to_test)
        mock_file1.SomeHelper.assert_called_once()

    @patch('file2.file1')
    def test_calculate_2(self, mock_file1):
        inst = mock_file1.SomeHelper.return_value
        inst.my_var = 2
        to_test = MyClass.calculate()
        self.assertFalse(to_test)
        mock_file1.SomeHelper.assert_called_once()


if __name__ == '__main__':
    unittest.main()

Unit test result with coverage report:

..
----------------------------------------------------------------------
Ran 2 tests in 0.002s

OK
Name                                       Stmts   Miss  Cover   Missing
------------------------------------------------------------------------
src/stackoverflow/50242955/file1.py            3      1    67%   3
src/stackoverflow/50242955/file2.py            8      0   100%
src/stackoverflow/50242955/test_file2.py      16      0   100%
------------------------------------------------------------------------
TOTAL                                         27      1    96%

Source code: https://github.com/mrdulin/python-codelab/tree/master/src/stackoverflow/50242955

Lin Du
  • 88,126
  • 95
  • 281
  • 483