4

I am trying to write some unit tests for an application and I using python mock. I am familiar with other mocking libraries and haven't had much trouble until now. I am trying to mock a chained call on an attribute set within the init block of the parent class. Here is an example of what I need:

class ApplicationUnderTest:

    def __init__(self):
      self.attributeBeginningChain = SomeClass(False)

    def methodWithChain(self):
      object = self.attributeBeginningChain.methodOfSomeClass()

I need the chained call to throw an error. I have tried resolving this in the following manner:

@patch.object(SomeClass(False), 'methodOfSomeClass', side_effect=ErrorClass)
def test_chained_call(self, mock_someclass):
    A = ApplicationUnderTest.methodWithChain()
    self.assertTrue(mock_someclass.called)

The last assertion fails so I am pretty sure this isn't the way to do this. I have also tried:

@patch('ApplicationUnderTest.attributeBeginningChain')
def test_chained_call(self, mock_someclass):
    mock_someclass.methodOfSomeClass.side_effect = ErrorClass
    A = ApplicationUnderTest.methodWithChain()
    self.assertTrue(mock_someclass.called)

That throws the error:

AttributeError: package.ApplicationUnderTest does not have the attribute 'attributeBeginningChain'

I cannot make alterations to the code under test, so my question is how can I mock chained calls made on attributes set under the _init__ function? I have read that this is not possible but surely there must be a work around? Can I perhaps somehow instruct the mock fixture to react to the call itself rather than the attribute object via autospec?

1 Answer 1

1

attributeBeginningChain instance attribute is set by __init__ so the patched static value that you set by patch call in ApplicationUnderTest call will be override by __init__ call.

You should patch ApplicationUnderTest instance instead:

def test_chained_call(self):
    A = ApplicationUnderTest()
    with patch.object(A, 'attributeBeginningChain') as mock_someclass:
        mock_someclass.methodOfSomeClass.side_effect = ErrorClass
        with self.assertRaise(ErrorClass):
            A.methodWithChain()

Another possibility is to patch directly SomeClass.methodOfSomeClass

@patch('package.SomeClass.methodOfSomeClass', side_effect=ErrorClass)
def test_chained_call(self, mock_methodOfSomeClass):
    with self.assertRaise(ErrorClass):
        ApplicationUnderTest().methodWithChain()

I'm not sure where your objects are and so how you should patch them: take a look at where to patch to understand how you should use patch calls.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the reply! I haven't tried this yet (moved on to other things) but I will check this out and respond when I get back to it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.