1

test_client/wclient.py

import json import requests client = requests.session() def setup(): response = REST_CLIENT.post( "https://placeholder.com", auth=(placeholder, placeholder), data={"grant_type": "client_credentials"}, ) status_code = response.status_code if status_code in OK_STATUS: payload = json.loads(response.content, object_pairs_hook=OrderedDict) else: payload = response.text msg = ( "Status Code %s" % status_code ) logger.error(msg) raise ValueError(msg) return payload["access_token"] 

Test File: test_client/test_client.py

import mock import wclient @mock.patch("test_client.wclient") def test_taxes_pitney_bowes_setup_success(resp): resp.return_value.post.return_value.status_code = "200" wclient.pitney_bowes_setup() 

Status Code <MagicMock name='REST_CLIENT.post().status_code' id='4868492200'>

How can I mock the module's methods and attributes with mock.patch()? I've read through pages of stack overflow posts but I'm getting confused with all the different ways to enforce a magic mock.

I've tried mocking:

resp.return_value.post.return_value.status_code resp.return_value.post.return_value.status_code.return_value resp.post.return_value.status_code resp.post.return_value.status_code.return_value resp.post.status_code resp.post.status_code.return_value 

1 Answer 1

2

I think there are numerous ways of actually doing the mock (see the many methods in Mocking Method Calls In Python). The way I like to do it and find easy for simple mocks is:

For functions: @patch('module.print', lambda x: None)

For attributes: @patch('module.cwd', os.path.join(os.getcwd(), "folder"))

This blog post might be helpful for you: https://medium.com/uckey/how-mock-patch-decorator-works-in-python-37acd8b78ae.

Let me know if you have more questions.

Edit: To add multiple mocks just add another attribute:

import wclient @mock.patch("test_client.wclient") @mock.patch("another_attribute", "value") @mock.patch("another_function", lambda x, y: x + y) def test_taxes_pitney_bowes_setup_success(resp): resp.return_value.post.return_value.status_code = "200" wclient.pitney_bowes_setup() 
Sign up to request clarification or add additional context in comments.

8 Comments

The blog posts helps my general understanding but I guess I don't really see how it helps the current problem at hand. @patch('module.print', lambda x: None) will set the value to a function, won't it? Edit: Accidentally hit the save edits. Continuing, what if I wanted to keep a generic mock object, but be able to have return values for multiple attributes, beyond just status_code? What if I wanted to do it for status_code and text? What if I wanted to be able to mock both posts and gets within the same method?
Correct, it'll change the print function in the module to return None. You can use this to return any value and mock out a function, or use it to change a variable to a particular value (see the attribute mock). Edit: you can add multiple patches above your test to specify different attributes and function. You also can change that lambda to take in multiple arguments and return multiple arguments based on that input. I can add this example to the answer above.
Are you saying that to mock both status_code and text for a post object, I would need to mock the post method? Or are you suggesting I need to mock the status_code and text attributes?
To follow up with the new, edited post. In this scenario, the MagicMock object is resp. With multiple mock.patch decorators, what is effectively being mocked by resp? Is it test_client.wclient? How can one object account for more than one match? EDIT: I understand the another_attribute and another_function have their return values within the decorator. My mistake! But that doesn't fix the status code not being properly mocked.
I don't think your solution answers my question. None of these suit the situation at hand.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.