আমি কীভাবে অনুরোধগুলি এবং প্রতিক্রিয়াটিকে উপহাস করতে পারি?


221

পাইথনস মডিউলটিকে উপহাস করার জন্য আমি পাইথনস মক প্যাকেজটি ব্যবহার করার চেষ্টা করছি requests। আমাকে নীচে দৃশ্যে কাজ করার জন্য বেসিক কলগুলি কী?

আমার ভিউ.পি-তে আমার একটি ফাংশন রয়েছে যা বিভিন্ন সময় বিভিন্ন অনুরোধ করে get

def myview(request):
  res1 = requests.get('aurl')
  res2 = request.get('burl')
  res3 = request.get('curl')

আমার পরীক্ষার ক্লাসে আমি এরকম কিছু করতে চাই তবে সঠিক পদ্ধতি কলগুলি বের করতে পারি না

ধাপ 1:

# Mock the requests module
# when mockedRequests.get('aurl') is called then return 'a response'
# when mockedRequests.get('burl') is called then return 'b response'
# when mockedRequests.get('curl') is called then return 'c response'

ধাপ ২:

আমার ভিউ কল করুন

ধাপ 3:

প্রতিক্রিয়া যাচাই করুন 'একটি প্রতিক্রিয়া', 'বি প্রতিক্রিয়া', 'সি প্রতিক্রিয়া'

আমি কীভাবে পদক্ষেপ 1 সম্পূর্ণ করতে পারি (অনুরোধের মডিউলটি উপহাস করে)?


5
এখানে ওয়ার্কিং লিঙ্কটি রয়েছে cra.mr/2014/05/20/mocking-requests-with-responses
যোগেশ লেলে

উত্তর:


277

এইভাবে আপনি এটি করতে পারেন (আপনি এই ফাইলটি যেমন চালাতে পারেন):

import requests
import unittest
from unittest import mock

# This is the class we want to test
class MyGreatClass:
    def fetch_json(self, url):
        response = requests.get(url)
        return response.json()

# This method will be used by the mock to replace requests.get
def mocked_requests_get(*args, **kwargs):
    class MockResponse:
        def __init__(self, json_data, status_code):
            self.json_data = json_data
            self.status_code = status_code

        def json(self):
            return self.json_data

    if args[0] == 'http://someurl.com/test.json':
        return MockResponse({"key1": "value1"}, 200)
    elif args[0] == 'http://someotherurl.com/anothertest.json':
        return MockResponse({"key2": "value2"}, 200)

    return MockResponse(None, 404)

# Our test case class
class MyGreatClassTestCase(unittest.TestCase):

    # We patch 'requests.get' with our own method. The mock object is passed in to our test case method.
    @mock.patch('requests.get', side_effect=mocked_requests_get)
    def test_fetch(self, mock_get):
        # Assert requests.get calls
        mgc = MyGreatClass()
        json_data = mgc.fetch_json('http://someurl.com/test.json')
        self.assertEqual(json_data, {"key1": "value1"})
        json_data = mgc.fetch_json('http://someotherurl.com/anothertest.json')
        self.assertEqual(json_data, {"key2": "value2"})
        json_data = mgc.fetch_json('http://nonexistenturl.com/cantfindme.json')
        self.assertIsNone(json_data)

        # We can even assert that our mocked method was called with the right parameters
        self.assertIn(mock.call('http://someurl.com/test.json'), mock_get.call_args_list)
        self.assertIn(mock.call('http://someotherurl.com/anothertest.json'), mock_get.call_args_list)

        self.assertEqual(len(mock_get.call_args_list), 3)

if __name__ == '__main__':
    unittest.main()

গুরুত্বপূর্ণ দ্রষ্টব্য: আপনার MyGreatClassশ্রেণি যদি অন্য প্যাকেজে থাকে তবে বলুন my.great.package, আপনাকে my.great.package.requests.getকেবল 'অনুরোধ.জেট' না দিয়ে উপহাস করতে হবে। সেক্ষেত্রে আপনার পরীক্ষার কেসটি দেখতে এমন হবে:

import unittest
from unittest import mock
from my.great.package import MyGreatClass

# This method will be used by the mock to replace requests.get
def mocked_requests_get(*args, **kwargs):
    # Same as above


class MyGreatClassTestCase(unittest.TestCase):

    # Now we must patch 'my.great.package.requests.get'
    @mock.patch('my.great.package.requests.get', side_effect=mocked_requests_get)
    def test_fetch(self, mock_get):
        # Same as above

if __name__ == '__main__':
    unittest.main()

উপভোগ করুন!


2
মকরেসপনস ক্লাসটি দুর্দান্ত ধারণা! আমি কোনও অতিথিকে জাল করার চেষ্টা করছিলাম es প্রতিক্রিয়া শ্রেণীর বস্তু কিন্তু এটি সহজ ছিল না। আমি আসল জিনিসের জায়গায় এই মকরেসপন্সটি ব্যবহার করতে পারি। ধন্যবাদ!
যোশি

@ যোশি হ্যাঁ, পাইথনের শোকগুলি ঘিরে আমার মাথাটি জড়ানোর জন্য আমার কিছুটা সময় লেগেছে তবে এটি আমার পক্ষে বেশ ভালভাবে কাজ করে!
জোহানেস ফারেনক্রুগ

10
আর পাইথন 2.x মধ্যে শুধু প্রতিস্থাপন from unittest import mockসঙ্গে import mockএবং বাকি হিসাবে কাজ করে। আপনার mockআলাদাভাবে প্যাকেজ ইনস্টল করতে হবে ।
haridsv

3
ফ্যান্টাস্টিক। আমি পাইথন 3 সামান্য পরিবর্তন করতে হবে mock_requests_getপ্রয়োজন yieldপরিবর্তে returnপাইথন মধ্যে iterators ফিরে 3. পরিবর্তনের কারণ
erip

1
মূলত এই প্রশ্নটিই জিজ্ঞাসা করছিল। আমি উপায়গুলি বের করেছি (অ্যাপ্লিকেশনটিকে প্যাকেজে প্যাক করুন এবং কল করার জন্য একটি টেস্ট_ক্লিয়েন্ট () ঠিক করুন)। পোস্টের জন্য ধন্যবাদ যদিও, এখনও কোডের মেরুদণ্ডটি ব্যবহার করছিল।
সুইসাইড বানি

141

প্রতিক্রিয়া গ্রন্থাগার ব্যবহার করে দেখুন :

import responses
import requests

@responses.activate
def test_simple():
    responses.add(responses.GET, 'http://twitter.com/api/1/foobar',
                  json={'error': 'not found'}, status=404)

    resp = requests.get('http://twitter.com/api/1/foobar')

    assert resp.json() == {"error": "not found"}

    assert len(responses.calls) == 1
    assert responses.calls[0].request.url == 'http://twitter.com/api/1/foobar'
    assert responses.calls[0].response.text == '{"error": "not found"}'

সমস্ত বিদ্রূপ নিজেকে সেট আপ করার উপর একটি দুর্দান্ত সুবিধা সরবরাহ করে

এর রয়েছে HTTPretty :

এটি requestsগ্রন্থাগারের সাথে সুনির্দিষ্ট নয় , কিছু উপায়ে আরও শক্তিশালী যদিও আমি পেয়েছি যে এটি যে অনুরোধগুলি আটকেছিল তা পরিদর্শন করার জন্য এটি নিজেকে এত ভাল ধার দেয় না, যা responsesবেশ সহজেই ঘটে

এর রয়েছে httmock


এক নজরে, আমি responsesএকটি ওয়াইল্ডকার্ড ইউআরএল ম্যাচ করার কোনও উপায় দেখিনি - এটি, "ইউআরএল এর শেষ অংশটি গ্রহণ করুন, এটি একটি মানচিত্রে সন্ধান করুন এবং সংশ্লিষ্ট মানটি ফিরিয়ে দিন" এর মতো কলব্যাক যুক্তি প্রয়োগ করুন। এটি কি সম্ভব, এবং আমি কেবল এটি মিস করছি?
স্কুবো

1
@scubbo আপনি URL PARAM যেমন একটি প্রি-কম্পাইল Regex প্রেরণ এবং কলব্যাক শৈলী ব্যবহার করতে পারেন github.com/getsentry/responses#dynamic-responses এই আপনি ওয়াইল্ডকার্ড আচরণ আপনি আমি মনে করি চাও তাই দেব (হস্তান্তর URL প্রবেশ করতে পারবেন requestARG কলব্যাক
ফানক

48

আমার জন্য যা কাজ করেছে তা এখানে:

import mock
@mock.patch('requests.get', mock.Mock(side_effect = lambda k:{'aurl': 'a response', 'burl' : 'b response'}.get(k, 'unhandled request %s'%k)))

3
আপনি যদি পাঠ্য / এইচটিএমএল প্রতিক্রিয়াগুলি আশা করেন তবে এটি কাজ করবে। আপনি যদি কোনও REST এপিআই উপহাস করছেন, স্থিতি কোড ইত্যাদি চেক করতে চান তবে জোহানেস [ stackoverflow.com/a/28507806/3559967] এর উত্তর সম্ভবত যাওয়ার উপায় the
অ্যান্টনি

5
পাইথন 3 এর জন্য ব্যবহার করুন from unittest import mockdocs.python.org/3/library/unittest.mock.html
ফিনিক্স

32

আমি পৃথক মডিউলের জন্য পরীক্ষাগুলি লেখার জন্য অনুরোধ-মক ব্যবহার করেছি:

# module.py
import requests

class A():

    def get_response(self, url):
        response = requests.get(url)
        return response.text

এবং পরীক্ষা:

# tests.py
import requests_mock
import unittest

from module import A


class TestAPI(unittest.TestCase):

    @requests_mock.mock()
    def test_get_response(self, m):
        a = A()
        m.get('http://aurl.com', text='a response')
        self.assertEqual(a.get_response('http://aurl.com'), 'a response')
        m.get('http://burl.com', text='b response')
        self.assertEqual(a.get_response('http://burl.com'), 'b response')
        m.get('http://curl.com', text='c response')
        self.assertEqual(a.get_response('http://curl.com'), 'c response')

if __name__ == '__main__':
    unittest.main()

আপনি কোথায় পাবেন ('স্ব, মি):'
ডেনিস ইভসিভ

16

আপনি অনুরোধগুলিকে এইভাবে উপহাস করবেন ost পোস্ট করুন, এটি আপনার http পদ্ধতিতে পরিবর্তন করুন

@patch.object(requests, 'post')
def your_test_method(self, mockpost):
    mockresponse = Mock()
    mockpost.return_value = mockresponse
    mockresponse.text = 'mock return'

    #call your target method now

1
আমি যদি কোনও ফাংশন উপহাস করতে চাই তবে কী হবে? এটির জন্য কীভাবে উপহাস করবেন: mockresponse.json () = {"কী": "মান"
im

1
@ প্রিমোজ, আমি এর জন্য একটি বেনামে ফাংশন / ল্যাম্বদা ব্যবহার করেছি:mockresponse.json = lambda: {'key': 'value'}
টেলার

1
বাmockresponse.json.return_value = {"key": "value"}
লার্স

5

আপনি যদি কোনও নকল প্রতিক্রিয়া উপহাস করতে চান, তবে এর অন্য উপায়টি হ'ল বেস এইচটিটিপ্রেসোনস শ্রেণির উদাহরণটি কেবল তাত্ক্ষণিকভাবে করা, যেমন:

from django.http.response import HttpResponseBase

self.fake_response = HttpResponseBase()

এটি আমি যা অনুসন্ধান করার চেষ্টা করছিলাম তার উত্তর: এটি একটি নকল জ্যাঙ্গো প্রতিক্রিয়া অবজেক্ট পান যা প্রায় e2e পরীক্ষার জন্য মিডলওয়্যারের গামুট মাধ্যমে এটি তৈরি করতে পারে। HttpResponseবরং ... বেস, আমার জন্য কৌশলটি করেছে। ধন্যবাদ!
কম_ঘোস্ট

4

অনুরোধগুলির চারপাশে কাজ করার একটি সম্ভাব্য উপায় হ'ল লাইব্রেরি বেটাম্যাক্স ব্যবহার করা, এটি সমস্ত অনুরোধ রেকর্ড করে এবং এরপরে আপনি যদি একই পরামিতিগুলির সাথে একই পাত্রে একটি অনুরোধ করেন তবে বেটাম্যাক্স রেকর্ড করা অনুরোধটি ব্যবহার করবে, আমি এটি ওয়েব ক্রলার পরীক্ষা করতে ব্যবহার করছি এবং এটি আমার অনেক সময় বাঁচায়

import os

import requests
from betamax import Betamax
from betamax_serializers import pretty_json


WORKERS_DIR = os.path.dirname(os.path.abspath(__file__))
CASSETTES_DIR = os.path.join(WORKERS_DIR, u'resources', u'cassettes')
MATCH_REQUESTS_ON = [u'method', u'uri', u'path', u'query']

Betamax.register_serializer(pretty_json.PrettyJSONSerializer)
with Betamax.configure() as config:
    config.cassette_library_dir = CASSETTES_DIR
    config.default_cassette_options[u'serialize_with'] = u'prettyjson'
    config.default_cassette_options[u'match_requests_on'] = MATCH_REQUESTS_ON
    config.default_cassette_options[u'preserve_exact_body_bytes'] = True


class WorkerCertidaoTRT2:
    session = requests.session()

    def make_request(self, input_json):
        with Betamax(self.session) as vcr:
            vcr.use_cassette(u'google')
            response = session.get('http://www.google.com')

https://betamax.readthedocs.io/en/latest/


লক্ষ্য করুন বিটাম্যাক্স শুধুমাত্র ডিজাইন করা হয়েছে সাথে কাজ করে অনুরোধ , যদি আপনি HTTP- র ক্যাপচার প্রয়োজন মত ব্যবহারকারী নিম্ন স্তরের HTTP- র এপিআই প্রণীত অনুরোধ httplib3 , অথবা বিকল্প সঙ্গে aiohttp বা এগুলির মতো ক্লায়েন্ট লিব boto ... ব্যবহার vcrpy পরিবর্তে যা নিম্ন স্তরের এ কাজ করে। Github.com/betamaxpy/betamax/issues/125-
লে হিবউ

0

যারা এখনও লড়াই করে যাচ্ছেন তাদের জন্য কেবলমাত্র সহায়ক ইঙ্গিত, urllib বা urllib2 / urllib3 থেকে অনুরোধগুলিতে রূপান্তর এবং প্রতিক্রিয়ার উপহাস করার চেষ্টা করছেন- আমার উপহাসটি প্রয়োগ করার সময় আমি কিছুটা বিভ্রান্তিকর ত্রুটি পেয়েছিলাম:

with requests.get(path, auth=HTTPBasicAuth('user', 'pass'), verify=False) as url:

বৈশিষ্ট্য ত্রুটি: __enter__

ঠিক আছে, অবশ্যই যদি আমি কীভাবে withকাজ করে (কিছু করি না) সম্পর্কে কিছু জানতাম তবে আমি জানতাম এটি একটি তদন্তমূলক, অপ্রয়োজনীয় প্রসঙ্গ ( পিইপি 343 থেকে )। অনুরোধের লাইব্রেরিটি ব্যবহার করার সময় অপ্রয়োজনীয় কারণ এটি মূলত হুডের নীচে আপনার জন্য একই জিনিস করে । withখালি মুছে ফেলুন এবং খালি requests.get(...)এবং বব এর চাচা ব্যবহার করুন


0

অ্যাসিঙ্ক এপি কলটি কীভাবে উপহাস করা যায় তা নির্ধারণ করতে আমার বেশ কষ্ট হয়েছে বলে আমি এই তথ্যটি যুক্ত করব।

একটি অ্যাসিঙ্ক কলকে উপহাস করার জন্য আমি এখানে যা করেছি।

এখানে আমি ফাংশনটি পরীক্ষা করতে চেয়েছি

async def get_user_info(headers, payload):
    return await httpx.AsyncClient().post(URI, json=payload, headers=headers)

আপনার এখনও মকরেসপনস ক্লাস প্রয়োজন

class MockResponse:
    def __init__(self, json_data, status_code):
        self.json_data = json_data
        self.status_code = status_code

    def json(self):
        return self.json_data

আপনি মকরেস্পোনসএসিঙ্ক ক্লাস যুক্ত করুন

class MockResponseAsync:
    def __init__(self, json_data, status_code):
        self.response = MockResponse(json_data, status_code)

    async def getResponse(self):
        return self.response

এই পরীক্ষা। এখানে গুরুত্বপূর্ণ বিষয়টি হ'ল আমি প্রতিক্রিয়াটি তৈরি করার আগে যেহেতু আরম্ভ করা ফাংশনটি অ্যাসিঙ্ক হতে পারে না এবং getResponse এ কল অ্যাসিঙ্ক হয় তাই এটি সমস্ত চেক আউট হয়ে গেছে।

@pytest.mark.asyncio
@patch('httpx.AsyncClient')
async def test_get_user_info_valid(self, mock_post):
    """test_get_user_info_valid"""
    # Given
    token_bd = "abc"
    username = "bob"
    payload = {
        'USERNAME': username,
        'DBNAME': 'TEST'
    }
    headers = {
        'Authorization': 'Bearer ' + token_bd,
        'Content-Type': 'application/json'
    }
    async_response = MockResponseAsync("", 200)
    mock_post.return_value.post.return_value = async_response.getResponse()

    # When
    await api_bd.get_user_info(headers, payload)

    # Then
    mock_post.return_value.post.assert_called_once_with(
        URI, json=payload, headers=headers)

যদি আপনার কাছে করার আরও ভাল উপায় থাকে তবে আমাকে বলুন তবে আমি মনে করি এটি এটির মতো পরিষ্কার।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.