Given this Python code:
elif request.method == 'DELETE':
try:
os.remove(full_file)
return jsonify({'results':'purged %s' % full_file})
except OSError as e:
if e.errno != errno.ENOENT:
raise
return jsonify({'results':'file not present: %s' % full_file})
I want to test all possible paths, including the exception handling. Using Mock, it's easy enough to raise an exception, which I do with this code:
with patch('os.remove', new=Mock(side_effect=OSError(errno.ENOENT))):
self.assertRaises(OSError, self.app.delete, file_URL) # broken
Mock raises an exception, which has a printed value of 2 (ENOENT) - but e.errno is set to NONE. And so far, I have not found a way to set it. The result is, the exception always gets re-raised, and I never reach the last line of code, in my unit test.
I've also tried creating a dummy class with errno set, and returning that. But unless it has *side_effect* set to be called, it doesn't raise an exception, and when I set side_effect, I don't get the object.errno as a return value.
Is there a way to have Mock raise an Exception, where that Exception object has the errno attribute set?
Raising exceptions with mocks A useful attribute is side_effect . If you set this to an exception class or instance then the exception will be raised when the mock is called. >>> mock = Mock(side_effect=Exception('Boom!
Just assign the exception to side_effect instead: mockedObj. raiseError. side_effect = Exception("Test") . You don't have to no: and his edit has a third way of doing it where he is making a Mock with the side effect set, but its still a valid, and good thing to know how to do in testing.
side_effect: A function to be called whenever the Mock is called. See the side_effect attribute. Useful for raising exceptions or dynamically changing return values. The function is called with the same arguments as the mock, and unless it returns DEFAULT , the return value of this function is used as the return value.
Only use a mock (or test double) “when testing things that cross the dependency inversion boundaries of the system” (per Bob Martin). If I truly need a test double, I go to the highest level in the class hierarchy diagram above that will get the job done. In other words, don't use a mock if a spy will do.
Pass two arguments to OSError constructor. (First one should be errno
).
For example:
>>> OSError(2).errno
>>> OSError(2, 'message').errno
2
>>> OSError(2, 'message').strerror
'message'
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