Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use python Mock side_effect to act as a Class method in unit test

I am testing a custom API in python that makes http requests, but I don't want to make a request to the real external system every time I run the unit tests. I am using python's mock library with a side_effect function to dynamically fake the API response. How do I get the side_effect method to behave like a class method?

import requests

class MyApiClass():
    def make_request(self, params):
        return requests.get('http://someurl.com', params=params)

    def create_an_object(self, params):
        return self.make_request(params)

import unittest, mock

def side_effect_func(self, params):
    if params['name'] == 'Specific Name':
        return {'text': 'Specific Action'}
    else:
        return {'text': 'General Action'}

class MyApiTest(unittest.TestCase):
    def setUp(self):
        super(MyApiTest, self).setUp()
        mocked_method = mock.Mock(side_effect=side_effect_func)
        MyApiClass.make_request = mocked_method

    def test_create_object(self):
        api = MyApiClass()
        params = {'name': 'Specific Name'}
        r = api.create_an_object(params) # Complains that two arguments are needed!
        self.assertEqual(r['text'], 'Specific Action')

I get this error

TypeError: side_effect_func() takes exactly 2 arguments (1 given)

but I want side_effect_func to pass api as the first argument. Appreciate any help!

like image 643
conman Avatar asked Oct 30 '13 14:10

conman


1 Answers

The simplest way would probably be to just make your mock method take a single argument, then reference MyApiClass statically within the mock method itself. Otherwise, you could try mocking the class object itself (basically making a mock metaclass) or maybe using a factory that utilizes partial to build a mock class method on the fly. But if the single argument/static reference method would work for you, that seems the best to me.

Also, from the Mock docs, there's mocking an unbound method using patch, which looks like it may be more what you need.

like image 177
Silas Ray Avatar answered Sep 30 '22 19:09

Silas Ray