development

요청 라이브러리를 사용하는 Python 앱 단위 테스트

big-blog 2020. 12. 8. 18:54
반응형

요청 라이브러리를 사용하는 Python 앱 단위 테스트


Kenneth Reitz의 요청 라이브러리를 사용하여 REST 작업을 수행하는 응용 프로그램을 작성 중이며 요청 이 모듈 수준 메서드를 통해 메서드를 제공하기 때문에 이러한 응용 프로그램을 단위 테스트하는 좋은 방법을 찾기 위해 고군분투하고 있습니다.

제가 원하는 것은 양측 간의 대화를 종합하는 능력입니다. 일련의 요청 주장 및 응답을 제공합니다.


특별히 요청을 사용하는 경우 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?'

좀 더 일반적인 것을 원한다면 (예를 들어, 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"

HTTPretty는 훨씬 더 많은 기능을 제공합니다. 모의 상태 코드, 스트리밍 응답, 회전 응답, 동적 응답 (콜백 포함)도 제공합니다.


실제로 라이브러리에 최종 사용자 단위 테스트에 대한 빈 페이지가 있지만 사용자 편의성과 사용 용이성을 목표로하는 것은 조금 이상합니다. 그러나 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)

Mocker 와 같은 모의 라이브러리를 사용 하여 요청 라이브러리에 대한 호출을 가로 채서 지정된 결과를 반환 할 수 있습니다.

매우 간단한 예로서 요청 라이브러리를 사용하는 다음 클래스를 고려하십시오.

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

Here's a unit test that intercepts the call to requests.get and returns a specified result for testing:

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()

When I run this unit test I get the following result:

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

OK

using mocker like in srgerg's answer:

def replacer(method, endpoint, json_string):
    from mocker import Mocker, ANY, CONTAINS
    mocker = Mocker()
    result = mocker.mock()
    result.json()
    mocker.count(1, None)
    mocker.result(json_string)
    replacement = mocker.replace("requests." + method)
    replacement(CONTAINS(endpoint), params=ANY)
    self.mocker.result(result)
    self.mocker.replay()

For the requests library, this would intercept the request by method and endpoint you're hitting and replace the .json() on the response with the json_string passed in.


Missing from these answers is requests-mock.

From their page:

>>> import requests
>>> import requests_mock

As a context manager:

>>> with requests_mock.mock() as m:

...     m.get('http://test.com', text='data')
...     requests.get('http://test.com').text
...
'data'

Or as a decorator:

>>> @requests_mock.mock()
... def test_func(m):
...     m.get('http://test.com', text='data')
...     return requests.get('http://test.com').text
...
>>> test_func()
'data'

참고URL : https://stackoverflow.com/questions/9559963/unit-testing-a-python-app-that-uses-the-requests-library

반응형