我写了一个unittest来测试请求包的超时
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
答案 0 :(得分:5)
我在这里看到两个问题。一个可以直接解决您的问题,另一个是轻微滥用Mocking框架,进一步简化了您的实现。
首先,根据您希望测试断言的方式,直接解决您的问题,您实际上在这里要做的是:
requests.get = get
你应在这里使用side_effect
来帮助提高你的例外。根据{{3}}:
side_effect允许你执行副作用,包括提高 调用mock时的异常
考虑到这一点,你真正需要做的就是:
requests.get.side_effect = get
这应该让你的例外加注。但是,您可能可能面临此错误:
TypeError: catching classes that do not inherit from BaseException is not allowed
这可以通过实际阅读documentation关于为什么会发生这种情况的好答案来解释 。有了这个答案,采取这个建议实际上只是模拟你需要将有助于完全解决你的问题。所以,最后,您的代码实际上看起来像这样,使用模拟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更好地利用unittest中的内容来进一步简化此操作。这最终只会声明在调用方法时引发异常。此外,您不需要 来创建一个会引发超时的新方法,您实际上可以简单地声明您的模拟获取将具有引发异常的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()
我希望这有帮助!
答案 1 :(得分:0)
patch('my_module.requests')
将使用新的模拟对象替换my_module.requests
,但在您的测试方法中,您将替换直接导入的requests.get
方法,因此替换原始请求模块,这意味着更改不会反映在您的模块中。
如果在您的测试方法中将其替换为my_module
中的请求模拟,则应该有效:
my_module.requests.get = get