Responses學(xué)習(xí)筆記

Responses

Responses - A utility for mocking out the Python Requests library,主要用于Web Service mocking。

安裝

使用pip3 install responses

基本使用

responses的使用主要是靠修飾器@responses.activate實(shí)現(xiàn)setup和teardown,以及responses.add()加入期望的返回值

import responses
import requests
from unittest import TestCase
from requests.exceptions import ConnectionError


class Demo(TestCase):

    #進(jìn)行responses的setup和teardown
    @responses.activate
    def test_basic(self):
        #確定response的詳細(xì)內(nèi)容
        responses.add(responses.GET,
                      'https://nbaplayerprofile.com/api/1/kawhi_leonard',
                      json={
                         'team': 'San Antonio Spurs',
                          'personal': {
                              'DOB': '6/29/1991',
                              'Ht': '67',
                              'Wt': '230'
                          }
                      },
                      status=200)

        expected_Kawhi_profile = {
                         'team' : 'San Antonio Spurs',
                          'personal' : {
                              'DOB' : '6/29/1991',
                              'Ht' : '67',
                              'Wt' : '230'
                          }
                      }
        #發(fā)送了兩次請(qǐng)求
        resp = requests.get('https://nbaplayerprofile.com/api/1/kawhi_leonard')
        resp1 = requests.get('https://nbaplayerprofile.com/api/1/kawhi_leonard')

        #對(duì)獲得的response進(jìn)行驗(yàn)證
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(resp1.json(), expected_Kawhi_profile)
        #responses.calls會(huì)記錄所有的請(qǐng)求響應(yīng)情況,可以利用起來進(jìn)行驗(yàn)證
        self.assertEqual(len(responses.calls), 2)
        self.assertEqual(responses.calls[0].request.url, 'https://nbaplayerprofile.com/api/1/kawhi_leonard')
        self.assertEqual(responses.calls[1].response.text, '{"team": "San Antonio Spurs", "personal": {"DOB": "6/29/1991", "Ht": "67", "Wt": "230"}}')

        # 錯(cuò)誤的請(qǐng)求地址 驗(yàn)證會(huì)產(chǎn)生ConnectionError
        with self.assertRaises(ConnectionError):
            requests.get('https://nbaplayerprofile.com/api/1/')

    @responses.activate
    def test_error(self):
        #響應(yīng)的body設(shè)置為Exception(),模擬出錯(cuò)的情況
        responses.add(responses.GET,
                      'https://nbaplayerprofile.com/api/1/error',
                      body = Exception(),
                      status=500
        )
        #驗(yàn)證異常被raise
        with self.assertRaises(Exception):
           requests.get('https://nbaplayerprofile.com/api/1/error')

我們可以直接把響應(yīng)寫在add()里,也可以按照下面的方式傳遞:

import responses

responses.add(
    responses.Response(
        method='GET',
        url='http://example.com',
    ),
)

Dynamic Responses

如果我們不想要返回固定的body,而是根據(jù)請(qǐng)求的不同返回不同的body,這個(gè)就需要responses.add_callback()功能。具體做法很簡(jiǎn)單,寫一個(gè)callback方法處理request,然后返回一個(gè)tuple(status, headers, body),然后callback方法作為參數(shù)傳入到responses.add_callback()中,相當(dāng)于設(shè)置好了返回的status code, header和body。

    @responses.activate
    def test_dynamic_responses_text(self):
        #定義callback方法,request請(qǐng)求會(huì)作為參數(shù)傳入方法體,進(jìn)行處理
        def request_callback(request):
            headers = {}
            return (200, headers, str(request.body) + " this is from dynamic")
        #使用add_callback()定義請(qǐng)求,callback關(guān)鍵參數(shù)傳入處理方法
        responses.add_callback(responses.POST,
                               "https://nbaplayerprofile.com/api/1/foo",
                                callback = request_callback,
                                content_type = 'text/plain'
                               )

        resp = requests.post("https://nbaplayerprofile.com/api/1/foo", "I am request")
        #驗(yàn)證響應(yīng)文本是否被動(dòng)態(tài)處理,
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(resp.headers, {'Content-Type': 'text/plain'})
        self.assertEqual(resp.text, "I am request this is from dynamic")

    @responses.activate
    def test_dynamic_responses_json(self):
        #這個(gè)例子處理json
        def request_callback(request):
            payload = json.loads(request.body)
            headers = {'User-Agent': 'Firefox/12.0'}
            payload.update({'result': 'pass'})
            resp_body = payload
            return (200, headers, json.dumps(resp_body))

        responses.add_callback(responses.POST,
                               'https://nbaplayerprofile.com/api/1/createplayer',
                               callback=request_callback,
                               content_type='application/json')

        request_json_body = {'name': 'Di', 'gender': 'male'}

        resp = requests.post(
            'https://nbaplayerprofile.com/api/1/createplayer',
            json.dumps(request_json_body)
                             )
        self.assertEqual(resp.json(), {"name": "Di", "gender": "male", "result": "pass"})

        self.assertEqual(len(responses.calls), 1)
        self.assertEqual(responses.calls[0].request.url, 'https://nbaplayerprofile.com/api/1/createplayer')
        self.assertEqual(responses.calls[0].response.text, '{"name": "Di", "gender": "male", "result": "pass"}')
        self.assertEqual(responses.calls[0].response.headers['User-Agent'], 'Firefox/12.0')

使用context manager來定義response

除了上面說的@responses.activateresponses.add()方法外,responses也支持with關(guān)鍵字,作為context manager來定義。

# !/usr/bin/env python
# -*- coding: utf-8 -*-os
import responses
import requests
from unittest import TestCase

#不需要使用@responses.activate
class Demo1(TestCase):

    def test_context_manager(self):
        #使用with關(guān)鍵字和responses.RequestsMock()
        with responses.RequestsMock() as resp:
            #同樣使用add()方法定義
            resp.add(resp.GET,
                     'https://nbaplayerprofile.com/api/1/kawhi_leonard',
                     json={
                         'team': 'San Antonio Spurs',
                         'personal': {
                             'DOB': '6/29/1991',
                             'Ht': '67',
                             'Wt': '230'
                         }},
                     status=200,
                     content_type='application/json'
                     )

            expected_Kawhi_profile = {
                         'team' : 'San Antonio Spurs',
                          'personal' : {
                              'DOB' : '6/29/1991',
                              'Ht' : '67',
                              'Wt' : '230'
                          }
                      }

            # 發(fā)送了兩次請(qǐng)求
            resps = requests.get('https://nbaplayerprofile.com/api/1/kawhi_leonard')
            resps1 = requests.get('https://nbaplayerprofile.com/api/1/kawhi_leonard')

            # 對(duì)獲得的response進(jìn)行驗(yàn)證
            self.assertEqual(resps.status_code, 200)
            self.assertEqual(resps1.json(), expected_Kawhi_profile)

            # responses.calls會(huì)記錄所有的請(qǐng)求響應(yīng)情況,可以利用起來進(jìn)行驗(yàn)證
            #這里的responses就是with關(guān)鍵字定義的名稱
            self.assertEqual(len(resp.calls), 2)
            self.assertEqual(resp.calls[0].request.url, 'https://nbaplayerprofile.com/api/1/kawhi_leonard')
            self.assertEqual(resp.calls[1].response.text,
                             '{"team": "San Antonio Spurs", "personal": {"DOB": "6/29/1991", "Ht": "67", "Wt": "230"}}')

當(dāng)定義的mock service沒有被訪問的時(shí)候,AssertionError: Not all requests have been executed會(huì)被raise,這時(shí)候需要設(shè)置參數(shù)assert_all_requests_are_fired=False來避免這個(gè)異常。

def test_requests_fired(self):
    # 設(shè)置assert_all_requests_are_fired來避免AssertionError: Not all requests have been executed`
    with responses.RequestsMock(assert_all_requests_are_fired=False) as resp:
        # 同樣使用add()方法定義
        resp.add(resp.GET,
                 'https://nbaplayerprofile.com/api/1/kawhi_leonard',
                 json={
                     'team': 'San Antonio Spurs',
                     'personal': {
                         'DOB': '6/29/1991',
                         'Ht': '67',
                         'Wt': '230'
                     }},
                 status=200,
                 content_type='application/json'
                 )

同樣的,我們也可以定制化responses,這里需要使用response_callback參數(shù)。

def test_callback(self):
    #定義response_callback方法,接受一個(gè)responses為參數(shù),返回一個(gè)responses
    #這個(gè)例子中我們給responses加了一個(gè)屬性
    def response_callback(resp):
        resp.result = 'pass'
        return resp

    with responses.RequestsMock(response_callback=response_callback) as stub:
        stub.add(responses.GET,
                           "https://nbaplayerprofile.com/api/1/foo",
                            body="I am body"
                           )
        resps = requests.get("https://nbaplayerprofile.com/api/1/foo", "I am request")
        self.assertEqual(resps.text, "I am body")
        #驗(yàn)證callback方法寫入的新屬性
        self.assertEqual(resps.result, "pass")
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,533評(píng)論 19 139
  • https://nodejs.org/api/documentation.html 工具模塊 Assert 測(cè)試 ...
    KeKeMars閱讀 6,598評(píng)論 0 6
  • scrapy學(xué)習(xí)筆記(有示例版) 我的博客 scrapy學(xué)習(xí)筆記1.使用scrapy1.1創(chuàng)建工程1.2創(chuàng)建爬蟲模...
    陳思煜閱讀 13,067評(píng)論 4 46
  • 那雙“夢(mèng)蝶”舊了,總想著添雙新的,直到遇見這雙荷花樣式的繡鞋。它很特別,鞋面掛著鈴鐺,走起路來“叮鈴叮鈴叮鈴”……...
    蘇長亭閱讀 520評(píng)論 85 30
  • 我今天發(fā)燒了,頭疼的特別厲害!書上的字我沒有寫,所以我們組就沒有達(dá)標(biāo),我很難過。 我本來...
    王啟萱閱讀 217評(píng)論 0 0

友情鏈接更多精彩內(nèi)容