python unittest 之mock


1.什麼是mock
unittest.mock是一個用於在Python中進行單元測試的庫,Mock翻譯過來就是模擬的意思,顧名思義這個庫的主要功能是模擬一些東西。
它的主要功能是使用mock對象替代掉指定的Python對象,以達到模擬對象的行爲。
學過python自動化的對unittest並不陌生,unittest實際上是單元測試框架,
但對於單元測試,估計不少小夥伴都不懂,單元測試纔是自動化測試的至高境界,其中mock是單元測試的脊髓所在
2.mock能作什麼:
    1.先後端聯調,若是你是一個前端頁面開發,如今須要開發一個功能:    下一個訂單,支付頁面的接口,根據支付結果,支付成功,展現支付成功頁,支付失敗,展現支付失敗頁。    要完成此功能,你須要調用後端的接口,根據返回給你的結果,來展現不一樣的頁面。此時後端接口還沒開發好,
    做爲一個前端開發總不能等別人開發好了,你再開發,那你只有加班的命了。    爲了同步開發完成任務,此時,你能夠根據接口文檔的規定,把接口的地址和入參傳過去,而後本身mock接口的不一樣返回界面,來完成前端的開發任務    2.單元測試,單元測試的目的是測試某個小小單元的功能,但現實中開發的函數或方法都是有依賴關係的,好比b函數的參數,須要調用a函數的返回結果,可是我前面已經測試a函數了    這種狀況下,就不須要再測一次a函數了,此時就能夠用mock模塊來模擬調用這部份內容,並給出返回結果    3.第三方接口依賴,在作接口自動化的時候,有時候須要調用第三方的接口,可是別人公司的接口服務不受你的控制,有可能別人提供的測試環境今天服務給你開着,別人就關掉了,
    給自動化接口測試帶來不少的麻煩,此時就能夠本身寫一個mock-server來模擬接口的返回數據
3.mock環境準備
1.python2.x的版本,mock是一個獨立的模塊,須要用pip安裝
    pip install -U mock
3.從Python 3.3之後的版本mock已經合併到unittest模塊中了,是unittest單元測試的一部分,直接導入過來就行
    from unittest import mock
依賴關係
1.以下場景:支付是一個獨立的接口,由其它開發提供,根據支付的接口返回狀態去顯示失敗,仍是成功,這個是你須要實現的功能
也就是說你寫一個b功能,你的同事寫一個a功能,你的b功能須要根據a功能的結果去判斷,而後實現對應的功能。這就是存在依賴關係,你同事開發的進度你是沒法控制的
你要是等他開發完了,你再開發,那你就坐等加班吧.
2.如下是本身寫的 zhifu_statues()函數功能,大概設計以下,保存爲temple.py文件
# 保存爲temple.py
# coding:utf-8

def zhifu():
    '''假設這裏是一個支付的功能,未開發完
    支付成功返回:{"result": "success", "reason":"null"}
    支付失敗返回:{"result": "fail", "reason":"餘額不足"}
    reason返回失敗緣由
    '''
    pass

def zhifu_statues():
    '''根據支付的結果success or fail,判斷跳轉到對應頁面'''
    result = zhifu()
    print(result)
    try:
        if result["result"] == "success":
            return "支付成功"
        elif result["result"] == "fail":
            print("失敗緣由:%s" % result["reason"])
            return "支付失敗"
        else:
            return "未知錯誤異常"
    except:
        return "Error, 服務端返回異常!"

3.單元測試用例設計
# coding:utf-8
from unittest import mock
import unittest
import temple

class Test_zhifu_statues(unittest.TestCase):
    '''單元測試用例'''
    def test_01(self):
        '''測試支付成功場景'''
        # mock一個支付成功的數據
        temple.zhifu = mock.Mock(return_value={"result": "success", "reason":"null"})
        # 根據支付結果測試頁面跳轉
        statues = temple.zhifu_statues()
        print(statues)
        self.assertEqual(statues, "支付成功")

    def test_02(self):
        '''測試支付失敗場景'''
        # mock一個支付成功的數據
        temple.zhifu = mock.Mock(return_value={"result": "fail", "reason": "餘額不足"})
        # 根據支付結果測試頁面跳轉
        statues = temple.zhifu_statues()
        self.assertEqual(statues, "支付失敗")

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

2、
mock裏面另外一種實現方式,patch裝飾器的使用,patch() 做爲函數裝飾器,爲您建立模擬並將其傳遞到裝飾函數
官方文檔地址
patch簡介

1.unittest.mock.patch(target,new = DEFAULT,spec = None,create = False,spec_set = None,autospec = None,new_callable = None,** kwargs )
    target參數必須是一個str,格式爲'package.module.ClassName',    注意這裏的格式必定要寫對,若是你的函數或類寫在pakege名稱爲a下,b.py腳本里,有個c的函數(或類),那這個參數就寫「a.b.c」
    new參數若是沒寫,默認指定的是MagicMock
    spec=True或spec_set=True,這會致使patch傳遞給被模擬爲spec / spec_set的對象    new_callable容許您指定將被調用以建立新對象的不一樣類或可調用對象。默認狀況下MagicMock使用。

函數案例講解

1.接着,新建一個temple.py,寫入如下代碼
# 保存爲temple.py
# coding:utf-8

def zhifu():
    '''假設這裏是一個支付的功能,未開發完
    支付成功返回:{"result": "success", "reason":"null"}
    支付失敗返回:{"result": "fail", "reason":"餘額不足"}
    reason返回失敗緣由
    '''
    pass

def zhifu_statues():
    '''根據支付的結果success or fail,判斷跳轉到對應頁面'''
    result = zhifu()
    print(result)
    try:
        if result["result"] == "success":
            return "支付成功"
        elif result["result"] == "fail":
            print("失敗緣由:%s" % result["reason"])
            return "支付失敗"
        else:
            return "未知錯誤異常"
    except:
        return "Error, 服務端返回異常!"

2.用mock.patch實現以下:
# coding:utf-8
from unittest import mock
import unittest
import temple

class Test_zhifu_statues(unittest.TestCase):
    '''單元測試用例'''

    @mock.patch("temple.zhifu")
    def test_01(self, mock_zhifu):
        '''測試支付成功場景'''
        # 方法一:mock一個支付成功的數據
        # temple.zhifu = mock.Mock(return_value={"result": "success", "reason":"null"})

        # 方法二:mock.path裝飾器模擬返回結果
        mock_zhifu.return_value = {"result": "success", "reason":"null"}
        # 根據支付結果測試頁面跳轉
        statues = temple.zhifu_statues()
        print(statues)
        self.assertEqual(statues, "支付成功")

    @mock.patch("temple.zhifu")
    def test_02(self, mock_zhifu):
        '''測試支付失敗場景'''
        # mock一個支付成功的數據

        mock_zhifu.return_value = {"result": "fail", "reason": "餘額不足"}
        # 根據支付結果測試頁面跳轉
        statues = temple.zhifu_statues()
        self.assertEqual(statues, "支付失敗")

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

類和方法案例
1.若是前面的temple.py裏面不是函數,是寫的類和方法,如何去使用mock?
# 保存爲temple.py
# coding:utf-8
class Zhifu():
    def zhifu(self):
        '''假設這裏是一個支付的功能,未開發完
        支付成功返回:{"result": "success", "reason":"null"}
        支付失敗返回:{"result": "fail", "reason":"餘額不足"}
        reason返回失敗緣由
        '''
        pass
class Statues():
    def zhifu_statues(self):
        '''根據支付的結果success or fail,判斷跳轉到對應頁面'''
        result = Zhifu().zhifu()
        print(result)
        try:
            if result["result"] == "success":
                return "支付成功"
            elif result["result"] == "fail":
                print("失敗緣由:%s" % result["reason"])
                return "支付失敗"
            else:
                return "未知錯誤異常"
        except:
            return "Error, 服務端返回異常!"

2.用例設計以下

# coding:utf-8
from unittest import mock
import unittest
from temple_class import Zhifu,Statues

class Test_zhifu_statues(unittest.TestCase):
    '''單元測試用例'''

    @mock.patch("temple_class.Zhifu")
    def test_01(self, mock_Zhifu):
        '''測試支付成功場景'''
        a = mock_Zhifu.return_value  # 先返回實例,對類名稱替換
        # 經過實例調用方法,再對方法的返回值替換
        a.zhifu.return_value = {"result": "success", "reason":"null"}
        # 根據支付結果測試頁面跳轉
        statues = Statues().zhifu_statues()
        print(statues)
        self.assertEqual(statues, "支付成功")

    @mock.patch("temple_class.Zhifu")
    def test_02(self, mock_Zhifu):
        '''測試支付失敗場景'''
        b = mock_Zhifu.return_value  # 先返回實例,對類名稱替換
        # 經過實例調用方法,再對方法的返回值替換
        b.zhifu.return_value = {"result": "fail", "reason": "餘額不足"}
        # 根據支付結果測試頁面跳轉
        statues = Statues().zhifu_statues()
        print(statues)
        self.assertEqual(statues, "支付失敗")

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

3.至關於函數來講,這裏主要多一步,要先對類的名稱進行mock一次"a = mock_Zhifu.return_value",再經過實例去調用方法。


前端

相關文章
相關標籤/搜索