I wrote a unittest to test timeout with the requests package
my_module.py:
import requests
class MyException(Exception): pass
def my_method():
try:
r = requests.get(...)
except requests.exceptions.Timeout:
raise MyException()
Unittest:
from mock import patch
from unittest import TestCase
from requests.exceptions import Timeout
from my_module import MyException
@patch('my_module.requests')
class MyUnitTest(TestCase):
def my_test(self, requests):
def get(*args, **kwargs):
raise Timeout()
requests.get = get
try:
my_module.my_method(...)
except MyException:
return
self.fail("No Timeout)
But when it runs, the try block in my_method
never catches the requests.exceptions.Timeout
There are two problems I see here. One that directly fixes your problem, and the second is a slight misuse of the Mocking framework that further simplifies your implementation.
First, to directly address your issue, based on how you are looking to test your assertion, what you are actually looking to do here:
requests.get = get
You should be using a side_effect
here to help raise your exception. Per the documentation:
side_effect allows you to perform side effects, including raising an exception when a mock is called
With that in mind, all you really need to do is this:
requests.get.side_effect = get
That should get your exception to raise. However, chances are you might face this error:
TypeError: catching classes that do not inherit from BaseException is not allowed
This can be best explained by actually reading this great answer about why that is happening. With that answer, taking that suggestion to actually only mock out what you need will help fully resolve your issue. So, in the end, your code will actually look something like this, with the mocked get
instead of mocked requests
module:
class MyUnitTest(unittest.TestCase):
@patch('my_module.requests.get')
def test_my_test(self, m_get):
def get(*args, **kwargs):
raise Timeout()
m_get.side_effect = get
try:
my_method()
except MyException:
return
You can now actually further simplify this by making better use of what is in unittest with assertRaises
instead of the try/except. This will ultimately just assert that the exception was raised when the method is called. Furthermore, you do not need to create a new method that will raise a timeout, you can actually simply state that your mocked get will have a side_effect
that raises an exception. So you can replace that entire def get
with simply this:
m_get.side_effect = Timeout()
However, you can actually directly put this in to your patch decorator, so, now your final code will look like this:
class MyUnitTest(unittest.TestCase):
@patch('my_module.requests.get', side_effect=Timeout())
def test_my_test(self, m_get):
with self.assertRaises(MyException):
my_method()
I hope this helps!
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