Mocking urllib3.PoolManager().request function with python

I have a function that makes a POST request using urllib3.PoolManager(). Now in the unit test I want to mock said request but having some difficulty. What's the correct way to do it? My code: I get this error "AssertionError: Expected 'request' to have been called once. Called 0 times."

I have a function that makes a POST request using urllib3.PoolManager(). Now in the unit test I want to mock said request but having some difficulty. What's the correct way to do it?

My code:

http = urllib3.PoolManager() # my func def func(event, context): ... resp = http.request('POST', url, body=encoded_msg) ... # unit test @patch('urllib3.PoolManager.request') def test_lambda_handler(self, mock_instance): mock_instance.return_value = Mock(status = "200", data = "success") res = func(event, []) mock_instance.request.assert_called_once() 

I get this error "AssertionError: Expected 'request' to have been called once. Called 0 times."

1 Answer

Since you call the constructor of the urllib3.PoolManager class in global (or module) scope. Reference: #where-to-patch

module b does import a and some_function uses a.SomeClass. ... In this case the class we want to patch is being looked up in the module and so we have to patch a.SomeClass instead: @patch('a.SomeClass')

Option 1: import the func after mocking urllib3.PoolManager class

lambda_handler.py:

import urllib3 import json http = urllib3.PoolManager() print('http: ', http) def func(event, context): url = 'http://localhost:3000' data = {'attribute': 'value'} encoded_msg = json.dumps(data).encode('utf-8') resp = http.request('POST', url, body=encoded_msg) 

test_lambda_handler.py:

import unittest import json from unittest import mock class TestLambdaHandler(unittest.TestCase): @mock.patch('urllib3.PoolManager') def test_lambda_handler(self, mock_PoolManager): from lambda_handler import func mock_http = mock_PoolManager.return_value event = {} func(event, []) mock_http.request.assert_called_once_with('POST', 'http://localhost:3000', body=json.dumps({'attribute': 'value'}).encode('utf-8')) unittest.main(verbosity=2) 

test result:

test_lambda_handler (__main__.TestLambdaHandler) ... http: <MagicMock name='PoolManager()' id='4475122928'> ok ---------------------------------------------------------------------- Ran 1 test in 0.063s OK Name Stmts Miss Cover Missing --------------------------------------------------------------------------------- src/stackoverflow/69890084/lambda_handler.py 9 0 100% src/stackoverflow/69890084/test_lambda_handler.py 12 0 100% --------------------------------------------------------------------------------- TOTAL 21 0 100% 

Option 2: mock the global variable http, you don't need to import the func after mocking

If you import the lambda_handler module at the top of the test file, the module lambda_handler will have a reference to the real urllib3.PoolManager so that it's too late for mocking.

import unittest import json from unittest import mock from lambda_handler import func class TestLambdaHandler(unittest.TestCase): @mock.patch('lambda_handler.http') def test_lambda_handler(self, mock_http): event = {} func(event, []) mock_http.request.assert_called_once_with('POST', 'http://localhost:3000', body=json.dumps({'attribute': 'value'}).encode('utf-8')) unittest.main(verbosity=2) 

test result:

http: <urllib3.poolmanager.PoolManager object at 0x1104b2610> test_lambda_handler (__main__.TestLambdaHandler) ... ok ---------------------------------------------------------------------- Ran 1 test in 0.002s OK Name Stmts Miss Cover Missing --------------------------------------------------------------------------------- src/stackoverflow/69890084/lambda_handler.py 9 0 100% src/stackoverflow/69890084/test_lambda_handler.py 11 0 100% --------------------------------------------------------------------------------- TOTAL 20 0 100% 

ncG1vNJzZmirpJawrLvVnqmfpJ%2Bse6S7zGiorp2jqbawutJobXJwaWV9eYCOpqaco5mjtG7B0aWjoppjYr2wu8ummKeZl5q%2Fbr7Eqqyeq6Ris7a6wq2gqKZdrLa1tIypsK2gn6M%3D

 Share!