import module
from x import X
class A:
def method():
return module.something(arg=X())
I created the following to unit test:
with patch('filename.module.something') as something_mock:
with patch('filename.X'): as x_mock:
a.method()
something_mock.assert_called_once_with(arg=x_mock.return_value)
x_mock.assert_called_once_with()
Someone mentioned that there is no need to mock filenme.X without an explanation. Is there other way to verify the call to something without mocking filename.X? How would I change the following assertion to verify the call?
something_mock.assert_called_once_with(arg=_____)
If create X is not a issue (i.e. db connection or network access) you can do your test without mock it.
You have follow alternatives:
Use mock's called attribute if you are not interested to check how your method call something_mock
Use mock.ANY if you would like to check that something_mock has called by arg keyword arg but you are not interested about what is the value
Use call_args to extract something_mock call arguments and by calls as tuple extract arg value
The first one is
assert something_mock.called
The second one is
something_mock.assert_called_once_with(arg=mock.ANY)
Finally the third one is
args, kwargs = something_mock.call_args
assert isinstance(kwarg['arg'], x.X)
Last option is quite the same to mock X but I wrote it just to show all possibilities.
Related
I have a main method that looks like this:
class Example:
...
def main(self):
self.one()
self.two(list)
self.three(self.four(4))
How to check if the calling main it calls the following methods inside it?
I have tried:
def setUp(self):
self.ex = example.Example()
def test_two(self):
# testing method two that has only list.append(int) and returns list
mock_obj = Mock()
self.ex.two(mock_obj, 1)
self.assertEqual(call.append(1),mock_obj.method_calls[0]) # works fine
mock_obj.method.called # throws False ...why?
def test_main(self):
with patch('example.Example') as a:
a.main()
print(a.mock_calls) # [call.main()]
...
def test_main(self):
mock_obj = Mock()
self.ex.main(mock_obj) # throws TypeError: main() takes exactly 1 argument (2 given)
print(mock_obj.method_calls) # expected one, two, three and four method calls
Realy need any help to be honest..
Using Python 2.6.6 with unittest and mock modules
With unit-testing you could in principle test if these four functions would actually be called. And, you could certainly do this by mocking all of them. However, you would need integration tests later anyway to be sure that the functions were called in the proper order, with the arguments in the proper order, arguments having values in the form expected by the callee, return values being in the expected form etc.
You can check all these things in unit-testing - but this has not much value, because if you have wrong assumptions about one of these points, your wrong assumptions will go into both your code and your unit-tests. That is, the unit-tests will test exactly against your wrong assumptions and will pass. Finding out about your wrong assumptions requires an integration test where the real caller and callee are brought together.
Summarized: Your main method is interaction dominated and thus should rather be tested directly by interaction-testing (aka integration-testing) rather than by unit-testing plus subsequent interaction-testing.
I've already browsed through the mock documentations, and i've seen some examples where mock has been used. But, being a newbie, i find it hard to use mock in my tests.
test_scoring.py - I am creating a test to make sure that a function DOES NOT get called whenever i create an item.
The function compute_score() that i'd like to mock is part of a class HistoryItem.
What i got so far is this :
#test_scoring.py
#mock.patch('monitor.report.history_item.HistoryItem.compute_score')
def test_save_device_report(self):
....
result = factory.create_history_item(jsn)
# If the mocked method gets called after the above function is used, then there should be an error.
So, how do I mock the method? I'm quite confused on how to use it, because there are different ways in the resources i found.
I'd really appreciate your help.
When using the patch method as a decorator, you need to specify a second parameter to your test function:
#mock.patch('monitor.report.history_item.HistoryItem.compute_score')
def test_save_device_report(self, my_mock_compute_score):
....
# Assuming the compute_score method will return an integer
my_mock_compute_score.return_value = 10
result = factory.create_history_item(jsn)
# Then simulate the call.
score = result.compute_score() # This call could not be necessary if the previous
# call (create_history_item) make this call for you.
# Assert method was called once
my_mock_compute_score.assert_called_once()
# Also you can assert that score is equal to 10
self.assertEqual(score, 10)
Note that the mocks should be used only when you've tested the patched method or object in another test.
Where to patch? -> https://docs.python.org/3/library/unittest.mock.html#where-to-patch
Edit
This patch is gonna to avoid a real call to compute_score(). However, after reread your post I can see you want to assert your function doesn't get called.
Hopefully, the called attribute is present in every mock you make, so for that you can use:
#mock.patch('monitor.report.history_item.HistoryItem.compute_score')
def test_save_device_report(self, my_mock_compute_score):
...
result = factory.create_history_item(jsn)
self.assertFalse(my_mock_compute_score.called)
...
I'd like to modify the arguments passed to a method in a module, as opposed to replacing its return value.
I've found a way around this, but it seems like something useful and has turned into a lesson in mocking.
module.py
from third_party import ThirdPartyClass
ThirdPartyClass.do_something('foo', 'bar')
ThirdPartyClass.do_something('foo', 'baz')
tests.py
#mock.patch('module.ThirdPartyClass.do_something')
def test(do_something):
# Instead of directly overriding its return value
# I'd like to modify the arguments passed to this function.
# change return value, no matter inputs
do_something.return_value = 'foo'
# change return value, based on inputs, but have no access to the original function
do_something.side_effect = lambda x, y: y, x
# how can I wrap do_something, so that I can modify its inputs and pass it back to the original function?
# much like a decorator?
I've tried something like the following, but not only is it repetitive and ugly, it doesn't work. After some PDB introspection.. I'm wondering if it's simply due to however this third party library works, as I do see the original functions being called successfully when I drop a pdb inside the side_effect.
Either that, or some auto mocking magic I'm just not following that I'd love to learn about.
def test():
from third_party import ThirdPartyClass
original_do_something = ThirdPartyClass.do_something
with mock.patch('module.ThirdPartyClass.do_something' as mocked_do_something:
def side_effect(arg1, arg2):
return original_do_something(arg1, 'overridden')
mocked_do_something.side_effect = side_effect
# execute module.py
Any guidance is appreciated!
You may want to use parameter wraps for the mock call. (Docs for reference.) This way the original function will be called, but it will have everything from Mock interface.
So for changing parameters called to original function you may want to try it like that:
org.py:
def func(x):
print(x)
main.py:
from unittest import mock
import org
of = org.func
def wrapped(a):
of('--{}--'.format(a))
with mock.patch('org.func', wraps=wrapped):
org.func('x')
org.func.assert_called_with('x')
result:
--x--
The trick is to pass the original underlying function that you still want to access as a parameter to the function.
Eg, for race condition testing, have tempfile.mktemp return an existing pathname:
def mock_mktemp(*, orig_mktemp=tempfile.mktemp, **kwargs):
"""Ensure mktemp returns an existing pathname."""
temp = orig_mktemp(**kwargs)
open(temp, 'w').close()
return temp
Above, orig_mktemp is evaluated when the function is declared, not when it is called, so all invocations will have access to the original method of tempfile.mktemp via orig_mktemp.
I used it as follows:
#unittest.mock.patch('tempfile.mktemp', side_effect=mock_mktemp)
def test_retry_on_existing_temp_path(self, mock_mktemp):
# Simulate race condition: creation of temp path after tempfile.mktemp
...
Writing some unit tests in python and using MagicMock to mock out a method that accepts a JSON string as input. In my unit test, I want to assert that it is called with given arguments, however I run into issues with the assert statement, since the ordering of objects within the dict doesn't matter, besides in the assert statement for the string. Simplified example of what I am trying to achieve below.
mock_funct = MagicMock()
# mocked function called elsewhere
expected = {"a":"a", "b":"b"}
mock_funct.assert_called_once_with(json.dumps(expected))
The above may pass or may fail due to the arbitrary ordering of the keys within the dict when it is dumped to json, ie both '{"a":"a", "b":"b"}' and '{"b":"b", "a":"a"}' are valid dumps but one would fail and one would pass, however I would like to write the test so that either would pass.
Unfortunately, you'll need to do your own checking here. You can get the calls from the mock via it's call_args_list attribute (or, simply call_args in this case since you have already asserted that it is called only once). I'll assume you're using unittest in my example code -- but it should be easy enough to adapt for any testing framework ...
mock_funct.assert_called_once_with(mock.ANY)
call = mock_funct.call_args
call_args, call_kwargs = call # calls are 2-tuples of (positional_args, keyword_args)
self.assertEqual(json.loads(call_args[0]), expected)
I've still used assert_called_once_with to make sure that the function was only called once with a single positional argument, but then I open up the call to look at that argument to check that it is correct.
I have been doing a lot of searching, and I don't think I've really found what I have been looking for. I will try my best to explain what I am trying to do, and hopefully there is a simple solution, and I'll be glad to have learned something new.
This is ultimately what I am trying to accomplish: Using nosetests, decorate some test cases using the attribute selector plugin, then execute test cases that match a criteria by using the -a switch during commandline invocation. The attribute values for the tests that are executed are then stored in an external location. The command line call I'm using is like below:
nosetests \testpath\ -a attribute='someValue'
I have also created a customized nosetest plugin, which stores the test cases' attributse, and writes them to an external location. The idea is that I can select a batch of tests, and by storing the attributes of these tests, I can do filtering on these results later for reporting purposes. I am accessing the method attributes in my plugin by overriding the "wantMethod" method with the code similar to the following:
def set_attribs(self, method, attribute):
if hasattr(method, attribute):
if not self.method_attributes.has_key(method.__name__):
self.method_attributes[method.__name__] = {}
self.method_attributes[method.__name__][attribute] = getattr(method, attribute)
def wantMethod(self, method):
self.set_attribs(method, "attribute1")
self.set_attribs(method, "attribute2")
pass
I have this working for pretty much all the tests, except for one case, where the test is uing the "yield" keyword. What is happening is that the methods that are generated are being executed fine, but then the method attributes are empty for each of the generated functions.
Below is the example of what I am trying to achieve. The test below retreives a list of values, and for each of those values, yields the results from another function:
#attr(attribute1='someValue', attribute2='anotherValue')
def sample_test_generator(self):
for (key, value) in _input_dictionary.items()
f = partial(self._do_test, key, value)
f.attribute1='someValue'
yield (lambda x: f(), key)
def _do_test(self, input1, input2):
# Some code
From what I have read, and think I understand, when yield is called, it would create a new callable function which then gets executed. I have been trying to figure out how to retain the attribute values from my sample_test_generator method, but I have not been successful. I thought I could create a partial method, and then add the attribute to the method, but no luck. The tests execute without errors at all, it just seems that from my plugin's perspective, the method attributes aren't present, so they don't get recorded.
I realize this a pretty involved question, but I wanted to make sure that the context for what I am trying to achieve is clear. I have been trying to find information that could help me for this particular case, but I feel like I've reached a stumbling block now, so I would really like to ask the experts for some advice.
Thanks.
** Update **
After reading through the feedback and playing around some more, it looks like if I modified the lambda expression, it would achieve what I am looking for. In fact, I didn't even need to create the partial function:
def sample_test_generator(self):
for (key, value) in _input_dictionary.items()
yield (lambda: self._do_test)
The only downside to this approach is that the test name will not change. As I am playing around more, it looks like in nosetests, when a test generator is used, it would actually change the test name in the result based on the keywords it contains. Same thing was happening when I was using the lambda expression with a parameter.
For example:
Using lamdba expression with a parameter:
yield (lambda x: self._do_test, "value1")
In nosetests plugin, when you access the test case name, it would be displayed as "sample_test_generator(value1)
Using lambda expression without a parameter:
yield (lambda: self._do_test)
The test case name in this case would be "sample_test_generator". In my example above, if there are multiple values in the dictionary, then the yield call would occur multiple times. However, the test name would always remain as "sample_test_generator". This is not as bad as when I would get the unique test names, but then not be able to store the attribute values at all. I will keep playing around, but thanks for the feedback so far!
EDIT
I forgot to come back and provide my final update on how I was able to get this to work in the end, there was a little confusion on my part at first, and after I looked through it some more, I figured out that it had to do with how the tests are recognized:
My original implementation assumed that every test that gets picked up for execution goes through the "wantMethod" call from the plugin's base class. This is not true when "yield" is used to generate the test, because at this point, the test method has already passed the "wantMethod" call.
However, once the test case is generated through the "yeild" call, it does go through the "startTest" call from the plug-in base class, and this is where I was finally able to store the attribute successfully.
So in a nut shell, my test execution order looked like this:
nose -> wantMethod(method_name) -> yield -> startTest(yielded_test_name)
In my override of the startTest method, I have the following:
def startTest(self, test):
# If a test is spawned by using the 'yield' keyword, the test names would be the parent test name, appended by the '(' character
# example: If the parent test is "smoke_test", the generated test from yield would be "smoke_test('input')
parent_test_name = test_name.split('(')[0]
if self.method_attributes.has_key(test_name):
self._test_attrib = self.method_attributes[test_name]
elif self.method_attributes.has_key(parent_test_name):
self._test_attrib = self.method_attributes[parent_test_name]
else:
self._test_attrib = None
With this implementation, along with my overide of wantMethod, each test spawned by the parent test case also inherits attributes from the parent method, which is what I needed.
Again, thanks to all who send replies. This was quite a learning experience.
Would this fix your name issue?
def _actual_test(x, y):
assert x == y
def test_yield():
_actual_test.description = "test_yield_%s_%s" % (5, 5)
yield _actual_test, 5, 5
_actual_test.description = "test_yield_%s_%s" % (4, 8) # fail
yield _actual_test, 4, 8
_actual_test.description = "test_yield_%s_%s" % (2, 2)
yield _actual_test, 2, 2
Rename survives #attr too.
does this work?
#attr(attribute1='someValue', attribute2='anotherValue')
def sample_test_generator(self):
def get_f(f, key):
return lambda x: f(), key
for (key, value) in _input_dictionary.items()
f = partial(self._do_test, key, value)
f.attribute1='someValue'
yield get_f(f, key)
def _do_test(self, input1, input2):
# Some code
The Problem ist that the local variables change after you created the lambda.