By "internal function", I mean a function that is called from within the same module it is defined in.
I am using the mock library, specifically the patch decorators, in my unit tests. They're Django unit tests, but this should apply to any python tests.
I have one module with several functions, many of which call each other. For example (fictitious code, ignore the lack of decimal.Decimal):
TAX_LOCATION = 'StateName, United States' def add_tax(price, user): tax = 0 if TAX_LOCATION == 'StateName, UnitedStates': tax = price * .75 return (tax, price+tax) def build_cart(...): # build a cart object for `user` tax, price = add_tax(cart.total, cart.user) return cart
These are part of a deeper calling chain (func1 -> func2 -> build_cart -> add_tax), all of which are in the same module.
In my unit tests, I'd like to disable taxes to get consistent results. As I see it, my two options are 1) patch out TAX_LOCATION (with an empty string, say) so that add_tax doesn't actually do anything or 2) patch out add_tax to simply return (0, price).
However, when I try to patch either of these the patch seems to work externally (I can import the patched part inside the test and print it out, getting expected values), but seems to have no effect internally (the results I get from the code behave as if the patch were not applied).
My tests are like this (again, fictitious code):
from mock import patch from django.test import TestCase class MyTests(TestCase): @patch('mymodule.TAX_LOCATION', '') def test_tax_location(self): import mymodule print mymodule.TAX_LOCATION # '' mymodule.func1() self.assertEqual(cart.total, original_price) # fails, tax applied @patch('mymodule.add_tax', lambda p, u: (0, p)) def test_tax_location(self): import mymodule print mymodule.add_tax(50, None) # (0, 50) mymodule.func1() self.assertEqual(cart.total, original_price) # fails, tax applied
Does anyone know if it's possible for mock to patch out functions used internally like this, or am I out of luck?
When the test function then calls get_complex_data_structure() a mock object is returned and stored in the local name foo ; the very same object that mocked_function. return_value references in the above test; you can use that value to test if do_work() got passed the right object, for example.
mock provides a powerful mechanism for mocking objects, called patch() , which looks up an object in a given module and replaces that object with a Mock . Usually, you use patch() as a decorator or a context manager to provide a scope in which you will mock the target object.
Patching vs Mocking: Patching a function is adjusting it's functionality. In the context of unit testing we patch a dependency away; so we replace the dependency. Mocking is imitating. Usually we patch a function to use a mock we control instead of a dependency we don't control.
The answer: Clean up your darned imports
@patch('mymodule.TAX_LOCATION', '')
did indeed patch things appropriately, but since our imports at the time were very haphazard -- sometimes we imported mymodule.build_cart
, sometimes we imported project.mymodule.build_cart
-- instances of the "full" import were not patched at all. Mock couldn't be expected to know about the two separate import paths... without being told explicitly, anyway.
We've since standardized all our imports on the longer path, and things behave much more nicely now.
another option is to explicitly call patch on the function:
mock.patch('function_name')
and to support both running directly or from py.test etc:
mock.patch(__name__ + '.' + 'function_name')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With