How to mock function with arguments spanning lines - python

I'm patching in my test (python2.7):
args[1].return_value.getMarkToMarketReportWithSummary.return_value = ([], {})
and I can see the
the expected mocked method with the correct return value when debugging:
and calling it is all good:
But, the method has multiple arguments:
rows, summary = manager.getMarkToMarketReportWithSummary(
portfolios, report_data_map, account,
...
include_twrr=self.__include_twrr)
and when the test runner calls the method it fails and returns a MagicMock instead of expected above. It's because of the arguments, making the method call a string or something. It looks like this:
so the method name looks the same but it has the \n with the args, etc. What is this? Is it an onion? Because it is making me cry.
Evaluating it a after that gives one more attribute, this time with #LINE#, because, you know, rubbing salt in my eyes is its goal:
:_(

Related

python mocking: wrong number of arguments error

I am trying to use the mock library and basically patching some module functions. So, I have some existing code which looks like this:
#patch('loader.utils.run_raise_exception_if_fail')
#patch('time.time', return_value=123)
def test_export_ok(self, _, run_command_mock):
....
calls = run_command_mock.call_args_list
This sort of works fine and the test gets called and executed. I am trying to understand what these function arguments mean and where they are generated. I have not used the mocking functionality ever before.
Now, I am trying to mock another function and I added the following patch decorator:
#patch('assessment.utils.statistics', return_value={"counts": {'volume': 10, hits=10}})
Now, when I try and run this thing, I get the following error:
TypeError: test_export_ok() takes 2 positional arguments but 4 were given
I am confused as to the patch decorators and these function arguments to the actual test. The function signature for the statistics method looks as follows:
def statistics(collisions: np.ndarray,
obj_size: Union[List, Tuple]):
#patch('loader.utils.run_raise_exception_if_fail')
#patch('time.time', return_value=123)
def test_export_ok(self, a, b):
....
calls = run_command_mock.call_args_list
For whichever function you are writing the unit test, if there are some 2 inner functions getting called in the main function and u want to patch it. Add the 2 patch decorators with the corresponding return value. Add variables in the main test function "a,b" corresponding to the count of the patch decorators used.
Please try this.
The error for incorrect number of arguments given should be resolved.

Function not being called in multiprocessing

I am using multiprocessing as given below:
with ProcessPoolExecutor(max_workers=3) as exe:
result = exe.map(self.extraction, tokens)
tokens is a list. Problem is its not getting into extraction function. Tried with print statements within function, not printing at all.
I see two potential reasons why with the code you provide, your function isn't being called, but no error is occurring either:
1 - self.extraction does not have the right signature. If the supplied function isn't one that takes exactly one argument, it won't be called. In the case of a instance function (method), this does not include self. So your method's signature should look like this:
def extraction(self, token):
...
I ran into this case myself a few weeks ago and it cost me a few hours. It's strange that the framework does not complain about the function's signature, and yet doesn't call it either.
2 - tokens is an empty iterable. Since the function will be called once for each item in the iterable, if it is empty, it will never be called. If tokens isn't an iterable at all, it seems that you get an error stating this.
I found the issue and resolved it referring this link Multiprocessing: How to use Pool.map on a function defined in a class?
My code is working like this :
with ProcessPoolExecutor(max_workers=3) as exe:
result = exe.map(ExtractSuggestions.extract_suggestion, tokens)
ExtractSuggestions is my class

How to pass parameters in a Python Dispatch Table

I am trying to construct a dispatch the following way:
def run_nn(type=None):
print type, 'nn'
return
def run_svm(type=None):
print type, 'svm'
return
action = {'nn' : run_nn( type=None),
'svm' : run_svm(type=None),}
I want the function to be executed only when called with something like:
action.get('nn',type='foo')
With expectation it to print:
foo nn
But it breaks giving:
TypeError: get() takes no keyword arguments
What's the right way to do it?
Furthermore, two functions run_nn() and run_svm() were executed without even being called. I don't want that. How can I avoid it?
You're calling the functions while building the dictionary. You should instead put the function objects in the dict without calling them. And afterwards, get the appropriate function from the dict and call it with the keyword argument.
What you want is:
action = {'nn' : run_nn,
'svm' : run_svm,}
...
action.get('nn')(type='foo') # get function object from dict and then call it.
I'll suggest you use action['nn'] over action.get('nn') since you're not specifying any default callable in the get method; the get method returns None when you don't specify one. A KeyError is much more intuitive than a TypeError NoneType object is not callable in this scenario.
On another note, you can drop those return statements as you aren't actually returning anything. Your function will still return without them.
BTW, I have the feeling your function(s) want to change behavior depending on type (although your type is counter-intuitive as it is always a string). In any case, you may have a look at functools.singledispatch. That'll transform your function(s) into a single-dispatch generic function with the possibility to create several overloaded implementations.
Finally, although type does make for a good argument name, you will run into problems when you need to use the builtin type in your function.

Is it possible to limit mocked function calls count?

I have encountered a problem when I write a unit test. This is a chunck from an unit test file:
main.obj = MainObj.objects.create(short_url="a1b2c3")
with unittest.mock.patch('prj.apps.app.models.base.generate_url_string', return_value="a1b2c3") as mocked_generate_url_string:
obj.generate_short_url()
This is a chunk of code from the file 'prj.apps.app.models.base' (file which imports function 'generate_url_string' which is being mocked):
from ..utils import generate_url_string
.....................
def generate_short_url(self):
short_url = generate_url_string()
while MainObj.objects.filter(short_url=short_url).count():
short_url = generate_url_string()
return short_url
I want to show in the unit test that the function 'generate_short_url' doesn't return repeated values if some objects in the system have similar short_urls. I mocked 'generate_url_string' with predefined return result for this purpose.
The problem is that I couldn't limit number of calls of mocked function with this value, and as a result the code goes to an infinite loop.
I would like to call my function with predefined result ('a1b2c3') only once. After that I want function to work as usual. Something like this:
with unittest.mock.patch('prj.apps.app.models.base.generate_url_string', return_value="a1b2c3", times_to_call=1) as mocked_generate_url_string:
obj.generate_short_url()
But I see no any attributes like 'times_to_call' in a mocking library.
Is there any way to handle that ?
Define a generator that first yields the fixed value, then yields the return value of the real function (which is passed as an argument to avoid calling the patched value).
def mocked(x):
yield "a1b2c3"
while True:
yield x()
Then, use the generator as the side effect of the patched function.
with unittest.mock.patch(
'prj.apps.app.models.base.generate_url_string',
side_effect=mocked(prj.apps.app.models.base.generate_url_string)) as mocked_generate_url_string:
obj.generate_short_url()

How to test for the second parameter of a mocked method?

I am trying to mock the sendEmails() method and would like to test if the second parameter is called with "test#test.com" email address.
#mock.patch('apps.dbank.management.commands.optin_invites.OptinBase.sendEmails')
def test_x_send_emails(self, send_emails_mock):
oi = OptinInvitesX()
oi.compute(True, "test#test.com")
self.assertTrue(send_emails_mock.assert_called_with(???, test_email_address="test#test.com"))
I could utilise assert_called_with but I don't care about the first parameter for this test case. Is there a way to say accept anything for first parameter?
You are describing the basic usage of mock.ANY:
Sometimes you may need to make assertions about some of the arguments in a call to mock, but either not care about some of the arguments or want to pull them individually out of call_args and make more complex assertions on them.
To ignore certain arguments you can pass in objects that compare equal to everything. Calls to assert_called_with() and assert_called_once_with() will then succeed no matter what was passed in.
So, in your case, you could use:
# only asserting on 'test_email_address' argument:
send_emails_mock.assert_called_with(mock.ANY, test_email_address="test#test.com")
Note that you don't really want to use self.assertTrue on that line. The mock method is its own assertion.

Categories