0

I'm trying to create some pytest unit tests on a custom ansible module. I'm trying to mock the boto3 client and just test the logic of the class. I moved the initialization of boto into a class method so I can patch the class and replace it with a mock object.

Patch seems to be successful, the "_init_boto" method is returning a mock object. But I can't figure out how to set the return value so that "describe_stacks(..)" returns a custom reponse, or assert on the calls on the mock. Sample code:

cf_stack_exists.py:

import boto3
class CfStackExistsSimplified:

    def __init__(self, aws_profile) -> None:
        super().__init__()
        self.aws_profile = aws_profile
        self.boto_client = self._init_boto(aws_profile)

    def _init_boto(self):
        session = boto3.session.Session(profile_name=self.aws_profile)
        return session.client('cloudformation')

    def exec(self):
        response = self.boto_client.describe_stacks(
            StackName=self.aws_profile
        )
        return response

test_myclass.py:

from unittest.mock import patch
from cf_stack_exists import CfStackExistsSimplified

class TestCfStackExists:
    @patch.object(CfStackExistsSimplified, "_init_boto")
    def test_example(self, mock_init_boto):
        myclass = CfStackExistsSimplified(aws_profile="dev")
        response = myclass.exec()
        print(f"\n{mock_init_boto.mock_calls}\n")
        mock_init_boto.describe_stacks().assert_called()

When I run this it fails with the error:

...
>           raise AssertionError(msg)
E           AssertionError: Expected 'mock' to have been called.
...

But the print statement is showing that it has been called?

[call('dev'), call().describe_stacks(StackName='dev')]

I really can't figure out how to assert this mock, tried lots of different assert commands. Any help much appreciated!!

1 Answer 1

1

By placing parentheses after the mocked function object describe_stacks, you're calling the function again, getting the child Mock object returned by the mock call, not the mocked function object that has the call records.

To assert that a mocked function is called, call the assert_called method of the mocked function object itself.

Conversely, to access a child Mock object returned by a call to a Mock object, which is the case of self.boto_client since it is assigned with what's returned by calling self._init_boto (mocked as mock_init_boto), you should place parentheses after the parent Mock object.

Change:

mock_init_boto.describe_stacks().assert_called()

to:

mock_init_boto().describe_stacks.assert_called()
Sign up to request clarification or add additional context in comments.

Comments

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.