99999久久久久久亚洲,欧美人与禽猛交狂配,高清日韩av在线影院,一个人在线高清免费观看,啦啦啦在线视频免费观看www

熱線電話:13121318867

登錄
首頁(yè)大數(shù)據(jù)時(shí)代Python 中 Mock 到底該怎么玩?一篇文章告訴你
Python 中 Mock 到底該怎么玩?一篇文章告訴你
2021-01-21
收藏

來源:AirPython

作者:星安果

Python 中 Mock 到底該怎么玩?一篇文章告訴你

1. 前言

微服務(wù)架構(gòu)下,由于各類服務(wù)開發(fā)進(jìn)度的不一致,導(dǎo)致聯(lián)調(diào)工作經(jīng)常會(huì)存在不確定性,進(jìn)而導(dǎo)致項(xiàng)目延期

在實(shí)際工作中,為了保證項(xiàng)目進(jìn)度,我們經(jīng)常需要針對(duì)部分未完成模塊及不穩(wěn)定模塊采用 Mock 方式,以驗(yàn)證已開發(fā)完的模塊

本篇文章將介紹 Python 實(shí)現(xiàn) Mock 的幾種常見方式

2. Mock 介紹

Mock 測(cè)試:在測(cè)試驗(yàn)證過程中,對(duì)于那些尚未完成或不穩(wěn)定的對(duì)象,用一個(gè)虛擬對(duì)象來替代,以便測(cè)試的測(cè)試方法

因此,這個(gè)虛擬的對(duì)象是 Mock 對(duì)象,Mock 對(duì)象是真實(shí)對(duì)象在調(diào)試期間的代替品

它的優(yōu)勢(shì)包含:

  • 前、后端并行開發(fā)
  • 模擬無法訪問的資源
  • 隔離系統(tǒng),避免臟數(shù)據(jù)干擾測(cè)試結(jié)果
  • 3.1 mock

    在 Python 3.3 之前使用 mock,需要先安裝依賴

    # 安裝mock依賴
    pip3 install mock

    假設(shè) Product 類中有 2 個(gè)方法

  • get_product_status_by_id
  • buy_product
  • 其中,get_product_status_by_id 方法還沒有實(shí)現(xiàn);buy_product 方法依賴于 
    get_product_status_by_id 方法的返回值

    # product_impl.py
    class Product(object):
    def __init__(self):
    pass
    def get_product_status_by_id(self, product_id):
    """
    通過商品id獲取產(chǎn)品信息(Mock)
    :return:
    """
    # 待實(shí)現(xiàn)查詢數(shù)據(jù)庫(kù)的業(yè)務(wù)邏輯
    pass
    def buy_product(self, product_id):
    """
    購(gòu)買產(chǎn)品(真實(shí)邏輯)
    :return:
    """
    # 產(chǎn)品信息
    # {"id":1,"name":"蘋果","num":23}
    product = self.get_product_status_by_id(product_id)
    if product.get("num") >= 1:
    result = {"status": 0, "msg": "購(gòu)買成功!"}
    else:
    result = {"status": 1, "msg": "購(gòu)買失敗,庫(kù)存不足!"}
    return result

    Mock 的步驟如下:
    導(dǎo)入使用 mock 中的 patch 方法作為測(cè)試方法的裝飾器,對(duì) get_product_status_by_id 
    方法進(jìn)行 Mock,方法參數(shù)為 Mock 對(duì)象測(cè)試方法中,對(duì)該 Mock 對(duì)象設(shè)置一個(gè)返回值調(diào)用并斷言from 
    mock import patch from mock_.product_impl import Product @patch('mock_.product_impl
    .Product.get_product_status_by_id') def test_succuse(mock_get_product_status_by_id):     
    # Mock方法,指定一個(gè)返回值     mock_get_product_status_by_id.return_value = 
    {"id": 1, "name": "蘋果", "num": 23}
    
        product = Product()
    
        assert product.buy_product(1).get("status") == 0 需要注意的是,
    Mock 此方法的時(shí)候,必須制定該方法的完整路徑使用 @patch.object 同樣能完成 Mock,
    不同的是,@patch.object 包含 2 個(gè)參數(shù)第一個(gè)參數(shù)為該方法所在的類;第二個(gè)參數(shù)為方法名from 
    mock import patch from mock_.product_impl import Product # Mock一個(gè)方法 # @patch.object:
    對(duì)象、方法名 @patch.object(Product, 'get_product_status_by_id') def test_succuse
    (mock_get_product_status_by_id):   
    # Mock方法,指定一個(gè)返回值     mock_get_product_status_by_id.return_value = 
    {"id": 1, "name": "蘋果", "num": 23}
        product = Product()
    
        assert product.buy_product(1).get("status") == 0

    3.2 unittest.mock

    Python 3.3 之后,mock 作為標(biāo)準(zhǔn)庫(kù),已經(jīng)內(nèi)置到 unittest 中了

    還是以 3.1 的場(chǎng)景為例,使用 unittest 編寫一個(gè)測(cè)試用例

    Mock 步驟如下:

  • 導(dǎo)入 unittest 框架中的 mock 文件
  • 實(shí)例化 Product 對(duì)象
  • mock.Mock(return_value=*) 方法對(duì) get_product_status_by_id 方法進(jìn)行 Mock
  • 調(diào)用并斷言
  • import unittest
    from unittest import mock
    from unittest_mock.product_impl import Product
    class TestProduct(unittest.TestCase):
    def test_success(self):
    # 成功結(jié)果
    mock_success_value = {"id": 1, "name": "蘋果", "num": 23}
    product = Product()
    product.get_product_status_by_id = mock.Mock(return_value=mock_success_value)
    # 調(diào)用實(shí)際函數(shù)
    assert product.buy_product(1).get("status") == 0
    if __name__ == "__main__":
    unittest.main()

    3.3 pytest.mock

    相比 unittest,pytest 由于強(qiáng)大的插件支持,用戶群體可能更大!

    如果項(xiàng)目本身使用的框架是 pytest,則 Mock 更建議使用 pytest-mock 這個(gè)插件

    # pytest依賴
    pip3 install pytest

    Mock 步驟如下:

  • 使用 pytest 編寫測(cè)試方法,參數(shù)為 mocker
  • 實(shí)例化 Product 對(duì)象
  • 使用 mocker.patch() 方法對(duì) get_product_status_by_id 方法進(jìn)行 Mock,并設(shè)置返回值
  • 調(diào)用并斷言
  • import pytest
    from pytest_mock_.product_impl import Product
    def test_buy_product_success(mocker):
    """
    購(gòu)買成功Mock
    :param mocker:
    :return:
    """
    # 實(shí)例化一個(gè)產(chǎn)品對(duì)象
    product = Product()
    # 對(duì)Product中的方法的返回值進(jìn)行Mock
    mock_value = {"id": 1, "name": "蘋果", "num": 23}
    # Mock方法
    # 注意:需要指定方法的完整路徑
    # mocker.patch 的第一個(gè)參數(shù)必須是模擬對(duì)象的具體路徑,第二個(gè)參數(shù)用來指定返回值
    product.get_product_status_by_id = mocker.patch("product_impl.Product.get_product_status_by_id",
    return_value=mock_value)
    # 調(diào)用購(gòu)買產(chǎn)品的方法
    result = product.buy_product(1)
    assert result.get("status") == 0

    需要注意的是,mocker.patch 方法第一個(gè)參數(shù)必須是 Mock 對(duì)象的完整路徑

    數(shù)據(jù)分析咨詢請(qǐng)掃描二維碼

    若不方便掃碼,搜微信號(hào):CDAshujufenxi

    數(shù)據(jù)分析師資訊
    更多

    OK
    客服在線
    立即咨詢
    客服在線
    立即咨詢
    ') } function initGt() { var handler = function (captchaObj) { captchaObj.appendTo('#captcha'); captchaObj.onReady(function () { $("#wait").hide(); }).onSuccess(function(){ $('.getcheckcode').removeClass('dis'); $('.getcheckcode').trigger('click'); }); window.captchaObj = captchaObj; }; $('#captcha').show(); $.ajax({ url: "/login/gtstart?t=" + (new Date()).getTime(), // 加隨機(jī)數(shù)防止緩存 type: "get", dataType: "json", success: function (data) { $('#text').hide(); $('#wait').show(); // 調(diào)用 initGeetest 進(jìn)行初始化 // 參數(shù)1:配置參數(shù) // 參數(shù)2:回調(diào),回調(diào)的第一個(gè)參數(shù)驗(yàn)證碼對(duì)象,之后可以使用它調(diào)用相應(yīng)的接口 initGeetest({ // 以下 4 個(gè)配置參數(shù)為必須,不能缺少 gt: data.gt, challenge: data.challenge, offline: !data.success, // 表示用戶后臺(tái)檢測(cè)極驗(yàn)服務(wù)器是否宕機(jī) new_captcha: data.new_captcha, // 用于宕機(jī)時(shí)表示是新驗(yàn)證碼的宕機(jī) product: "float", // 產(chǎn)品形式,包括:float,popup width: "280px", https: true // 更多配置參數(shù)說明請(qǐng)參見:http://docs.geetest.com/install/client/web-front/ }, handler); } }); } function codeCutdown() { if(_wait == 0){ //倒計(jì)時(shí)完成 $(".getcheckcode").removeClass('dis').html("重新獲取"); }else{ $(".getcheckcode").addClass('dis').html("重新獲取("+_wait+"s)"); _wait--; setTimeout(function () { codeCutdown(); },1000); } } function inputValidate(ele,telInput) { var oInput = ele; var inputVal = oInput.val(); var oType = ele.attr('data-type'); var oEtag = $('#etag').val(); var oErr = oInput.closest('.form_box').next('.err_txt'); var empTxt = '請(qǐng)輸入'+oInput.attr('placeholder')+'!'; var errTxt = '請(qǐng)輸入正確的'+oInput.attr('placeholder')+'!'; var pattern; if(inputVal==""){ if(!telInput){ errFun(oErr,empTxt); } return false; }else { switch (oType){ case 'login_mobile': pattern = /^1[3456789]\d{9}$/; if(inputVal.length==11) { $.ajax({ url: '/login/checkmobile', type: "post", dataType: "json", data: { mobile: inputVal, etag: oEtag, page_ur: window.location.href, page_referer: document.referrer }, success: function (data) { } }); } break; case 'login_yzm': pattern = /^\d{6}$/; break; } if(oType=='login_mobile'){ } if(!!validateFun(pattern,inputVal)){ errFun(oErr,'') if(telInput){ $('.getcheckcode').removeClass('dis'); } }else { if(!telInput) { errFun(oErr, errTxt); }else { $('.getcheckcode').addClass('dis'); } return false; } } return true; } function errFun(obj,msg) { obj.html(msg); if(msg==''){ $('.login_submit').removeClass('dis'); }else { $('.login_submit').addClass('dis'); } } function validateFun(pat,val) { return pat.test(val); }