在Python中使用mock模組進行單元測試__Python

來源:互聯網
上載者:User
為什麼需要Mock

假設現在系統有兩個模型A和B,其中A依賴B(例如A,B都是函數,A函數體內調用了B函數),但是B還沒完成,或者根本就不在控制之內;這時候又需要對A的功能進行單獨測試,就需要使用mock對象,類比出一個假的fake_B模組,雖然這個fake_B模組是假的,但是我們可以通過對它的行為進行定製來使他能夠看起來“像”B模組的功能,使A依賴fake_B,來對A的功能進行測試。同時,由於fake_B是完全可控的,除了可以定製B的屬性,傳回值之外,還可以對B模組的使用方式進行測試。


而在Python中可以使用mock和unittest.mock來產生這樣的mock對象。 用法簡介

首先需要建立一個mock對象

   >>>from mock import MagicMock   >>>fake_obj = MagicMock() 

然後可以通過return_value設定它的傳回值,當你調用這個mock對象時返回,傳回值可以是任何類型,變數,函數,類對象都可以。

    >>>fake_obj.return_value = 'This is a mock object'    >>>fake_obj()    'This is a mock object'

也可以通過side_effect指定它的副作用,這個副作用就是當你調用這個mock對象是會調用的函數,也可以選擇拋出一個異常,來對程式的錯誤狀態進行測試。

    >>>def b():    ...    print 'This is b'    ...    >>>fake_obj.side_effect = b    >>>fake_obj()    This is b    >>>fake_obj.side_effect = KeyError('This is b')    >>>fake_obj()    ...    KeyError: 'This is b'

同時也可以以一個對象base為基礎,拓展mock,使得mock獲得base的所有屬性和方法(但僅是介面相同,沒有實現),當調用不屬於base的屬性和方法時,會拋出AttributeError。這需要在建立mock對象的時候,在spec參數指定,前面的傳回值和副作用也可以在建立時進行指定。

    >>>class B:    ...    def __init__(self):    ...        self.a = 'a'    ...    >>>b = B()    >>>fake_obj = MagicMock(b)    <MagicMock spec='B' id='4370614160'>    >>>fake_obj.a    'a'    >>>fake_obj.b    AttributeError: Mock object has no attribute 'b'

還有一點需要強調的就是,如果要類比一個對象而不是函數,你可以直接在mock對象上添加屬性和方法,並且每一個添加的屬性都是一個mock對象,也就是說可以對這些屬性進行配置,並且可以一直遞迴的定義下去。

    >>>fake_obj.fake_a.return_value = 'This is fake_obj.fake_a'    >>>fake_obj.fake_a()    'This is fake_obj.fake_a'

在對mock對象進行一定的配置之後就是使用mock對象進行測試,這個模組採用的‘action-assertion’的方式進行測試,即先運行,再通過斷言進行測試。例如可以測試mock對象是否被調用,調用了幾次,如何被調用等等,mock對象本身提供了豐富的斷言方法,官方文檔中提供了詳盡的描述。

    >>>fake_obj = MagicMock(return_value = 1)    >>>fake_obj.assert_called()    AssertionError: Expected 'None' to have been called.    >>>fake_obj()    >>>fake_obj.assert_called()    >>>    >>>fake_obj(1,2,3,key=1)    >>>fake_obj.assert_called_with(1,2,3,key=1)    >>>

同時mock庫提供了patch函數來簡化mock對象對原對象的替換。patch可以作為裝飾器或者上下文管理器使用,這意味著在裝飾的函數和上下文管理器中,對應的類會被替換為mock對象。

    >>>from mock import patch    >>>@patch('__main__.SomeClass')    ... def function(normal_argument, mock_class):    ...     print(mock_class is SomeClass)       ...    >>>function(None)    True
參考資料

官方文檔 https://docs.python.org/3/library/unittest.mock.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.