Mock Confusion with Path - python

I have a test below using mock on Python 2.6.
#patch('testme.check.RE.query')
def test_check(query):
query.filter.one = MagicMock(return_value=None)
....
assert against_experiment(cl, ei, cd)
Inside the module I want to test, I have
def check_against_experiment(c, e, c):
re = RE.query.filter(RE.e_id == e).one()
Two questions:
When inspecting re = RE.query.filter(RE.e_id == e).one(), I see <MagicMock name='query.filter().one()' id='62856528'>.
Why isn't this returning None?
Another question is when I change #path('testme.check.RE.query') to #path('testme.check.RE.query') and change query.filter.one to query.one, I notice that nothing is mocked out. Why is this the case?

When you are calling RE.query.filter(RE.e_id == e) in your function-under-test, it is returning a new unconfigured MagicMock, and then you are calling its one function, which is generating that default return_value.
You probably want to set the return_value of filter to be a new Mock whose one function returns None.

Short answer is what you want to do is
query.filter.return_value.one.return_value = None
Default mock's return_value attribute is a MagickMock object (AFAIK allocated as lazy property).
IMHO try to avoid this kind of mock configurations, take your class/function more clear and narrow to avoid object browsing. These kind of test make source and tests tangled and create a solid fence to do refactoring.
For your second question I can just point you to Where to Patch must read document. From what you say is impossible to find the root cause by I can bet the answer is always in this documentation's chapter.

Related

Mocking a function that is passed in as a parameter during a class variable initialization

scuevals_api/resources/students.py:
def year_in_range(year):
return datetime.now().year <= year <= datetime.now().year + 10
class StudentsResource(Resource):
args = {
'graduation_year': fields.Int(required=True, validate=year_in_range),
}
...
I'm trying to mock year_in_range (to always return True) however, all my attempts have failed so far.
I'm using the decorator approach with mock.patch and have tried a ton of different targets, but the one I believe should be the correct one is:
#mock.patch('scuevals_api.resources.students.year_in_range', return_value=True)
The mock function never gets called, as in, it's not mocking correctly. I'm not getting any errors either.
My only remaining suspicions is that it has something to do with that the function is passed in to fields.Int as a param (hence the question title), but in my head, it shouldn't affect anything.
I'm clueless as to where this function should be mocked?
By the time mock has patched year_in_range it is too late. mock.patch imports the module specified by the string you provided and patches the name indicated within the module so it refers to a mock object - it does not fundamentally alter the function object itself. On import of scuevals_api.resources.students the body of the StudentsResource class will be executed and a reference to the original year_in_range saved within the StudentResource.args['graduation_year'] object, as a result making the name year_in_range refer to a mock object has no impact.
In this particular case you have a few options:
Assuming you're trying to test some functionality, instead of trying to mock year_in_range you can seed the database (?) with data that tests the condition
You can patch datetime.now which will be called by year_in_range
You can patch the member of StudentResource.args['graduation_year'] where the function passed to validate has been saved.
Thanks to the explanation by Chris Hunt, I came up with an alternative solution. It does modify the application code rather than the testing code, but if that is acceptable (which, in today's day and age probably should be, since having testable code is high priority), it is a really simple solution:
It's not possible to mock year_in_range since a reference to the original function is saved before the mocking is done. Therefore, "wrap" the function you want to mock with another function and pass the wrapper instead. Wrapping can be done in a nice and tidy way using lambda functions:
def year_in_range(year):
return datetime.now().year <= year <= datetime.now().year + 10
class StudentsResource(Resource):
args = {
'graduation_year': fields.Int(required=True, validate=lambda y: year_in_range(y)),
}
...
Now, when I mock year_in_range as stated in the question, it will work. The reason is because now a reference is saved to the lambda function, instead of to the original year_in_range (that won't be accessed until the lambda function runs, which will be during the test).

How to force "is not None" test

I have an API in Python which can return an object, or None if no object is found. I want to avoid run-time exceptions/crashes, etc., hence I want to force the users of my API, to do an is not None test.
For example:
x = getObject(...)
if x is not None:
print x.getName() #should be o.k.
y = getObject(...)
print y.getName() # print an error to the log
How can I achieve that?
In comparable code in C++, I can add a flag that will be checked when I call the getName(); the flag is set only upon comparing the object to NULL.
In Python, however, I am unable to overload the is operator. Are there any other ways I can achieve that functionality in Python?
You cannot force the use of if x is not None because you cannot override the behavior of id(). The is operator internally compares the ids of the two objects being compared, and you have no way of controlling that behavior.
However, you can force the use of if x != None or if not x == Noneby overriding the __eq__ and __ne__ methods of your class, respectively.
This is not good practice, however. As #Kevin has noted in the comments, is is the preferred operator to use when comparing to None.
What I would do is write clear and organized documentation for this API, and then clearly warn users that the instantiation could fail and return None. Then, gently nudge users towards good practices by providing an example with the built-in getattr function or an example with the is not None check.
Like it was already said, you can't override is behavior.
To do what you want, basically you can create a surrogate object that has a getName() function. To let the user check if the function failed, you can have the object evaluate to False. (This is a standard practice and I think this is better than making the object equal to None with the __eq__ operator). To do this, you can override override __nonzero__() having it return False.
Example:
class GetObjectFailed(object):
def __nonzero__():
return False
def getName():
return "An error has occurred" # You could specify a specific error message here...
x = getObject(...)
print x # prints "An error has occurred"
if x:
# This is the recommended way of doing things
# Do something with the object
x.proccess()
if x is not None:
# This will never work
x.proccess()
if x != None:
# This is possible but not recommended
x.proccess()

Getter with side effect

I create a class whose objects are initialized with
a bunch of XML code. The class has the ability to extract various parameters out of that XML and to cache them inside the object state variables. The potential amount of these parameters is large and most probably, the user will not need most of them. That is why I have decided to perform a "lazy" initialization.
In the following test case such a parameter is title. When the user tries to access it for the first time, the getter function parses the XML, properly initializes the state variable and return its value:
class MyClass(object):
def __init__(self, xml=None):
self.xml = xml
self.title = None
def get_title(self):
if self.__title is None:
self.__title = self.__title_from_xml()
return self.__title
def set_title(self, value):
self.__title = value
title = property(get_title, set_title, None, "Citation title")
def __title_from_xml(self):
#parse the XML and return the title
return title
This looks nice and works fine for me. However, I am disturbed a little bit by the fact that the getter function is actually a "setter" one in the sense that it has a very significant side effect on the object. Is this a legitimate concern? If so, how should I address it?
This design pattern is called Lazy initialization and it has legitimate use.
While the getter certainly performs a side-effect, that's not traditionally what one would consider a bad side-effect. Since the getter always returns the same thing (barring any intervening changes in state), it has no user-visible side-effects. This is a typical use for properties, so there's nothing to be concerned about.
Quite some years later but well: while lazy initialization is fine in itself, I would definitly not postpone xml parsing etc until someone accesses the object's title. Computed attributes are supposed to behave like plain attributes, and a plain attribute access will never raise (assuming the attribute exists of course).
FWIW I had a very similar case in some project I took over, with xml parsing errors happening at the most unexpected places, due to the previous developper using properties the very same way as in the OP example, and had to fix it by putting the parsing and validation part at instanciation time.
So, use properties for lazy initialization only if and when you know the first access will never ever raise. Actually, never use a property for anything that might raise (at least when getting - setting is a different situation). Else, dont use a property, make the getter an explicit method and clearly document it might raise this or that.
NB : using a property to cache something is not the problem here, this by itself is fine.

How to mock chained function calls in python?

I'm using the mock library written by Michael Foord to help with my testing on a django application.
I'd like to test that I'm setting up my query properly, but I don't think I need to actually hit the database, so I'm trying to mock out the query.
I can mock out the first part of the query just fine, but I am not getting the results I'd like when I chain additional things on.
The function:
#staticmethod
def get_policies(policy_holder, current_user):
if current_user.agency:
return Policy.objects.filter(policy_holder=policy_holder, version__agency=current_user.agency).distinct()
else:
return Policy.objects.filter(policy_holder=policy_holder)
and my test: The first assertion passes, the second one fails.
def should_get_policies_for_agent__user(self):
with mock.patch.object(policy_models.Policy, "objects") as query_mock:
user_mock = mock.Mock()
user_mock.agency = "1234"
policy_models.Policy.get_policies("policy_holder", user_mock)
self.assertEqual(query_mock.method_calls, [("filter", (), {
'policy_holder': "policy_holder",
'version__agency': user_mock.agency,
})])
self.assertTrue(query_mock.distinct.called)
I'm pretty sure the issue is that the initial query_mock is returning a new mock after the .filter() is called, but I don't know how to capture that new mock and make sure .distinct() was called on it.
Is there a better way to be testing what I am trying to get at? I'm trying to make sure that the proper query is being called.
Each mock object holds onto the mock object that it returned when it is called. You can get a hold of it using your mock object's return_value property.
For your example,
self.assertTrue(query_mock.distinct.called)
distinct wasn't called on your mock, it was called on the return value of the filter method of your mock, so you can assert that distinct was called by doing this:
self.assertTrue(query_mock.filter.return_value.distinct.called)

Can I unit test an inner function in python?

Is there any way to write unittests or doctests for innerfunc?
def outerfunc():
def innerfunc():
do_something()
return innerfunc()
Only if you provide a way to extract the inner function object itself, e.g.
def outerfunc(calltheinner=True):
def innerfunc():
do_something()
if calltheinner:
return innerfunc()
else:
return innerfunc
If your outer function insists on hiding the inner one entirely inside itself (never letting it percolate outside when properly cajoled to do so), your unit-tests are powerless to defeat this strong bid for extreme and total privacy;-).
This is actually an old open Python issue:
Issue 1650090: doctest doesn't find nested functions
There's a candidate patch (from 2007) that makes doctest find nested functions, but someone probably needs to push this.

Categories