2016-12-24 104 views
3

在我的Python代码,我期待的异常也可能会被调用方法requests.Session.request()后产生,例如这些:pytest:如何在单元测试期间强制引发异常?

  • requests.exceptions.ConnectTimeout
  • requests.exceptions.ReadTimeout
  • requests.exceptions.Timeout

当任何这些预期例外情况会提出,我会适当地处理它们,例如可能是重试情况。

我的问题是,我正在使用py.test进行单元测试,并且我故意要从我的代码的特定部分注入引发异常。例如,调用requests.Session.request()而不是返回有效的requests.Response的函数会产生requests.exception

我想确保我的代码能够成功处理来自其他包的预期和意外异常,其中包括来自requests的异常。

也许......是否有@decorator,我可以添加到上述函数在单元测试期间根据请求引发异常?

针对单元测试执行异常注入的建议? (我的问题的正确措辞将不胜感激。)

感谢您的答复!

下面是创建requests.Session,并呼吁整个单例类requests.Session.request()

class MyRequest(metaclass=Singleton): 

    def __init__(self, retry_tries=3, retry_backoff=0.1, retry_codes=None): 
     self.session = requests.session() 

     if retry_codes is None: 
      retry_codes = set(REQUEST_RETRY_HTTP_STATUS_CODES) 

     self.session.mount(
      'http', 
      HTTPAdapter(
       max_retries=Retry(
        total=retry_tries, 
        backoff_factor=retry_backoff, 
        status_forcelist=retry_codes, 
       ), 
      ), 
     ) 

    def request(self, request_method, request_url, **kwargs): 
     try: 
      return self.session.request(method=request_method, url=request_url, **kwargs) 
     except Exception as ex: 
      log.warning(
       "Session Request: Failed: {}".format(get_exception_message(ex)), 
       extra={ 
        'request_method': request_method, 
        'request_url': request_url 
       } 
      ) 
      raise 
+1

能告诉你在测试你的代码?特别是会话启动和使用的方式。谢谢。 – alecxe

+3

你可以注入一个假对象来创建请求,而不是硬编码'requests.Session'。你可以创建一个我们可以讨论的小例子吗?尽可能小(可能5-10行)。看看如何创建一个[mcve] –

+0

刚刚添加到这个问题的类实例方法,它的唯一目的是调用'requests.Session.request()'。这有帮助吗? – jeff00seattle

回答

1

您可以使用py.test的加薪,点击此处查看:http://doc.pytest.org/en/latest/assert.html#assertions-about-expected-exceptions

考虑到你的,你的代码可以采取以下措施:

from requests.exceptions import ConnectTimeout, ReadTimeout, Timeout 
from unittest.mock import patch 
import pytest 

class TestRequestService: 
    @patch('path_to_module.MyRequest') 
    def test_custom_request(self, my_request_mock): 
     my_request_mock.request.side_effect = ConnectTimeout 

     with pytest.raises(ConnectTimeout): 
      my_request_mock.request(Mock(), Mock()) 

此外,你可以利用pytest.parametrize(http://doc.pytest.org/en/latest/parametrize.html),以及:

from requests.exceptions import ConnectTimeout, ReadTimeout, Timeout 
from unittest.mock import patch 
import pytest 

class TestRequestService: 
    @pytest.mark.parametrize("expected_exception", [ConnectTimeout, ReadTimeout, Timeout]) 
    @patch('path_to_module.MyRequest') 
    def test_custom_request(self, my_request_mock, expected_exception): 
     my_request_mock.request.side_effect = expected_exception 
     with pytest.raises(expected_exception): 
      my_request_mock.request(Mock(), Mock()) 

在这里你可以找到一些参数多更多的例子:http://layer0.authentise.com/pytest-and-parametrization.html

相关问题