Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing integer to MagicMock not working inside unittest in python

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.

like image 602
RebeccaK375 Avatar asked May 08 '18 22:05

RebeccaK375


People also ask

What is the difference between mock and MagicMock?

With Mock you can mock magic methods but you have to define them. MagicMock has "default implementations of most of the magic methods.". If you don't need to test any magic methods, Mock is adequate and doesn't bring a lot of extraneous things into your tests.

Should I use mock MagicMock?

Mock vs. MagicMock is a subclass of Mock . It contains all magic methods pre-created and ready to use (e.g. __str__ , __len__ , etc.). Therefore, you should use MagicMock when you need magic methods, and Mock if you don't need them.

What is Autospec in Python Unittest?

Auto-speccing can be done through the autospec argument to patch, or the create_autospec() function. Auto-speccing creates mock objects that have the same attributes and methods as the objects they are replacing, and any functions and methods (including constructors) have the same call signature as the real object.

What is MagicMock in Python?

MagicMock. MagicMock objects provide a simple mocking interface that allows you to set the return value or other behavior of the function or object creation call that you patched. This allows you to fully define the behavior of the call and avoid creating real objects, which can be onerous.


1 Answers

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

like image 69
slideshowp2 Avatar answered Oct 28 '22 13:10

slideshowp2