Python Requests Mock 没有捕获超时异常
Python Requests Mock doesn't catch Timeout exception
我写了一个单元测试来测试请求包的超时
my_module.py:
import requests
class MyException(Exception): pass
def my_method():
try:
r = requests.get(...)
except requests.exceptions.Timeout:
raise MyException()
单元测试:
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)
但是当它运行时,my_method
中的 try 块永远不会捕获 requests.exceptions.Timeout
patch('my_module.requests')
将用新的模拟对象替换 my_module.requests
,但是在您的测试方法中,您替换了直接导入的 requests.get
方法,因此在原始请求模块上,它意味着更改不会反映在您的模块中。
如果在您的测试方法中将其替换为 my_module
中的模拟请求,它应该可以工作:
my_module.requests.get = get
我在这里看到两个问题。一个可以直接解决您的问题,第二个是对 Mocking 框架的轻微误用,进一步简化了您的实施。
首先,为了直接解决您的问题,根据您希望如何测试您的断言,您在这里实际想要做什么:
requests.get = get
您应该在这里使用side_effect
来帮助提出您的例外。根据 documentation:
side_effect allows you to perform side effects, including raising an
exception when a mock is called
考虑到这一点,您真正需要做的就是:
requests.get.side_effect = get
这应该让您提出例外。但是,您可能 可能 遇到此错误:
TypeError: catching classes that do not inherit from BaseException is not allowed
这可能是 最好的 通过实际阅读 很好的答案来解释为什么会发生这种情况。有了这个答案,采纳这个建议实际上只模拟出你 需要 的东西将有助于完全解决你的问题。所以,最后,您的代码实际上看起来像这样,使用模拟的 get
而不是模拟的 requests
模块:
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
实际上,您现在可以通过更好地使用 assertRaises
而不是 try/except 的单元测试来进一步简化此操作。这最终只会断言调用该方法时引发了异常。此外,您不需要 创建一个会引发超时的新方法,您实际上可以简单地声明您的模拟 get 将有一个引发异常的 side_effect
。所以你可以用这个简单地替换整个 def get
:
m_get.side_effect = Timeout()
然而,您实际上可以直接将其放入补丁装饰器中,因此,现在您的最终代码将如下所示:
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()
希望对您有所帮助!
我写了一个单元测试来测试请求包的超时
my_module.py:
import requests
class MyException(Exception): pass
def my_method():
try:
r = requests.get(...)
except requests.exceptions.Timeout:
raise MyException()
单元测试:
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)
但是当它运行时,my_method
中的 try 块永远不会捕获 requests.exceptions.Timeout
patch('my_module.requests')
将用新的模拟对象替换 my_module.requests
,但是在您的测试方法中,您替换了直接导入的 requests.get
方法,因此在原始请求模块上,它意味着更改不会反映在您的模块中。
如果在您的测试方法中将其替换为 my_module
中的模拟请求,它应该可以工作:
my_module.requests.get = get
我在这里看到两个问题。一个可以直接解决您的问题,第二个是对 Mocking 框架的轻微误用,进一步简化了您的实施。
首先,为了直接解决您的问题,根据您希望如何测试您的断言,您在这里实际想要做什么:
requests.get = get
您应该在这里使用side_effect
来帮助提出您的例外。根据 documentation:
side_effect allows you to perform side effects, including raising an exception when a mock is called
考虑到这一点,您真正需要做的就是:
requests.get.side_effect = get
这应该让您提出例外。但是,您可能 可能 遇到此错误:
TypeError: catching classes that do not inherit from BaseException is not allowed
这可能是 最好的 通过实际阅读 get
而不是模拟的 requests
模块:
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
实际上,您现在可以通过更好地使用 assertRaises
而不是 try/except 的单元测试来进一步简化此操作。这最终只会断言调用该方法时引发了异常。此外,您不需要 创建一个会引发超时的新方法,您实际上可以简单地声明您的模拟 get 将有一个引发异常的 side_effect
。所以你可以用这个简单地替换整个 def get
:
m_get.side_effect = Timeout()
然而,您实际上可以直接将其放入补丁装饰器中,因此,现在您的最终代码将如下所示:
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()
希望对您有所帮助!