Python unittest mock: Is it possible to mock the default arguments of a method during testing?

I have a method that accepts default arguments:

def build_url(endpoint, host=settings.DEFAULT_HOST): return '{}{}'.format(host, endpoint) 

I have a test case that uses this method:

 class BuildUrlTestCase(TestCase): def test_build_url(self): """ If host and endpoint are supplied result should be 'host/endpoint' """ result = build_url('/end', 'host') expected = 'host/end' self.assertEqual(result,expected) @patch('myapp.settings') def test_build_url_with_default(self, mock_settings): """ If only endpoint is supplied should default to settings""" mock_settings.DEFAULT_HOST = 'domain' result = build_url('/end') expected = 'domain/end' self.assertEqual(result,expected) 

If I drop the debug point in build_url and check this settings.DEFAULT_HOST attribute, the value mocked is returned. However, the test continues to fail, and the statement indicates that host assigned the value from my actual settings.py . I know this because the host keyword argument was set during import and my layout is not considered.

debugger

 (Pdb) settings <MagicMock name='settings' id='85761744'> (Pdb) settings.DEFAULT_HOST 'domain' (Pdb) host 'host-from-settings.com' 

Is there a way to override this value during testing so that I can implement the default path with the mocked settings object?

+6
source share
2 answers

Functions store default parameter values ​​in the func_defaults attribute when a function is defined, so you can fix it. Sort of

 def test_build_url(self): """ If only endpoint is supplied should default to settings""" with patch.object(build_url, 'func_defaults', ('domain',)): result = build_url('/end') expected = 'domain/end' self.assertEqual(result,expected) 

I use patch.object as a context manager, not a decorator, to avoid the unnecessary patch object passed as test_build_url argument.

+6
source

I applied a different answer to this question, but after the context manager, the corrected function was not the same as before.

My fixed function looks like this:

 def f(foo=True): pass 

In my test, I did the following:

 with patch.object(f, 'func_defaults', (False,)): 

When f called after (not in) the context manager, the default value completely disappeared, and did not return to the previous value. Calling f without arguments gave a TypeError error TypeError: f() takes exactly 1 argument (0 given)

Instead, I simply did this before my test:

 f.func_defaults = (False,) 

And this is after my test:

 f.func_defaults = (True,) 
0
source

Source: https://habr.com/ru/post/970260/


All Articles