Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock Class with original spec Python

I am trying to mock a class in Python using the Mock package, specifically, using the patch decorator in the test class.

from unittest import TestCase
from unittest.mock import Mock, patch

@patch("mypackage.subpackage.mymodule", autospec=True)
class MyClassTest(TestCase):
    def setUp(self):
        [...]

    def test_with_boundary_creates_job_flow_task(self):
        returned_value = self.some_class.return_something_from_my_module()

        self.assertIsInstance(returned_value, expected_value_class)

I would like my mock to have the original behavior of the class being mocked, i.e. unless I specifically mock an attribute/method, it should behave as in the provided class (with its logic & return value).

Thus, when testing a not mocked method but existing method in the original class, test should run successfully rather than failing with following (specific) error:

AssertionError: <class 'unittest.mock.MagicMock'> is not an instance of <class 'airflow.contrib.operators.emr_create_job_flow_operator.EmrCreateJobFlowOperator'>

Any ideas about how to achieve this?

like image 257
blamblam Avatar asked Feb 17 '26 04:02

blamblam


1 Answers

The reason for this error, is because a module is mocked, not class

AssertionError: <class 'unittest.mock.MagicMock'> is not an instance of 
<class ...EmrCreateJobFlowOperator'>

Change

@patch("mypackage.subpackage.mymodule"

To

@patch("mypackage.subpackage.mymodule.SomeClass"

I would like my mock to have the original behavior of the class being mocked,

I am afraid it is other way around, This will create an instance of App with all methods and attributes mocked, it is only useful when you want to mock the class esp the __init__ to use one method(or two)

mock_app = MagicMock(name='App', spec=App)
mock_app.method_one.return_value = whatever

I specifically mock an attribute/method, method_one, while app will have everything real except method_one

mock_app = MagicMock(name='App', 'method_one', spec=App)
mock_app.method_one.return_value = 'mocked value'
app = App()

In short, your patch will be

  from airflow.contrib.operators.emr_create_job_flow_operator import EmrCreateJobFlowOperator
  @patch.object(EmrCreateJobFlowOperator, 'the_method')
like image 185
Gang Avatar answered Feb 19 '26 16:02

Gang