Home > OS >  Mocking urllib3.PoolManager().request function with python
Mocking urllib3.PoolManager().request function with python

Time:11-10

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."

CodePudding user response:

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%
  • Related