单元测试使用请求库的python应用程序

Chr*_*s R 60 python testing unit-testing mocking python-requests

我正在编写一个使用Kenneth Reitz的请求库执行REST操作的应用程序,我正在努力寻找一种单独测试这些应用程序的好方法,因为请求通过模块级方法提供其方法.

我想要的是能够综合双方之间的对话; 提供一系列请求断言和响应.

小智 46

如果您使用特定请求尝试httmock.它简洁而优雅:

from httmock import urlmatch, HTTMock
import requests

# define matcher:
@urlmatch(netloc=r'(.*\.)?google\.com$')
def google_mock(url, request):
    return 'Feeling lucky, punk?'

# open context to patch
with HTTMock(google_mock):
    # call requests
    r = requests.get('http://google.com/')
print r.content  # 'Feeling lucky, punk?'
Run Code Online (Sandbox Code Playgroud)

如果你想要更通用的东西(例如模拟任何创建http调用的库),请访问httpretty.

几乎一样优雅:

import requests
import httpretty

@httpretty.activate
def test_one():
    # define your patch:
    httpretty.register_uri(httpretty.GET, "http://yipit.com/",
                        body="Find the best daily deals")
    # use!
    response = requests.get('http://yipit.com')
    assert response.text == "Find the best daily deals"
Run Code Online (Sandbox Code Playgroud)

HTTPretty功能更丰富 - 它还提供模拟状态代码,流响应,旋转响应,动态响应(带回调).


saa*_*aaj 32

实际上有点奇怪的是,该库有一个关于最终用户单元测试的空白页面,同时针对用户友好性和易用性.然而,Dropbox提供了一个易于使用的库,不出所料responses.这是它的介绍.它说他们没有使用httpretty,虽然没有说明失败的原因,并编写了一个类似API的库.

import unittest

import requests
import responses


class TestCase(unittest.TestCase):

  @responses.activate  
  def testExample(self):
    responses.add(**{
      'method'         : responses.GET,
      'url'            : 'http://example.com/api/123',
      'body'           : '{"error": "reason"}',
      'status'         : 404,
      'content_type'   : 'application/json',
      'adding_headers' : {'X-Foo': 'Bar'}
    })

    response = requests.get('http://example.com/api/123')

    self.assertEqual({'error': 'reason'}, response.json())
    self.assertEqual(404, response.status_code)
Run Code Online (Sandbox Code Playgroud)


srg*_*erg 23

您可以使用模拟库(如Mocker)拦截对请求库的调用并返回指定的结果.

作为一个非常简单的示例,请考虑使用请求库的此类:

class MyReq(object):
    def doSomething(self):
        r = requests.get('https://api.github.com', auth=('user', 'pass'))
        return r.headers['content-type']
Run Code Online (Sandbox Code Playgroud)

这是一个单元测试,它拦截调用requests.get并返回指定的测试结果:

import unittest
import requests
import myreq

from mocker import Mocker, MockerTestCase

class MyReqTests(MockerTestCase):
    def testSomething(self):
        # Create a mock result for the requests.get call
        result = self.mocker.mock()
        result.headers
        self.mocker.result({'content-type': 'mytest/pass'})

        # Use mocker to intercept the call to requests.get
        myget = self.mocker.replace("requests.get")
        myget('https://api.github.com', auth=('user', 'pass'))
        self.mocker.result(result)

        self.mocker.replay()

        # Now execute my code
        r = myreq.MyReq()
        v = r.doSomething()

        # and verify the results
        self.assertEqual(v, 'mytest/pass')
        self.mocker.verify()

if __name__ == '__main__':
    unittest.main()
Run Code Online (Sandbox Code Playgroud)

当我运行此单元测试时,我得到以下结果:

.
----------------------------------------------------------------------
Ran 1 test in 0.004s

OK
Run Code Online (Sandbox Code Playgroud)