Python如何在單元測(cè)試中給對(duì)象打補(bǔ)丁
問(wèn)題
你寫(xiě)的單元測(cè)試中需要給指定的對(duì)象打補(bǔ)丁, 用來(lái)斷言它們?cè)跍y(cè)試中的期望行為(比如,斷言被調(diào)用時(shí)的參數(shù)個(gè)數(shù),訪問(wèn)指定的屬性等)。
解決方案
unittest.mock.patch()
函數(shù)可被用來(lái)解決這個(gè)問(wèn)題。 patch()
還可被用作一個(gè)裝飾器、上下文管理器或單獨(dú)使用,盡管并不常見(jiàn)。 例如,下面是一個(gè)將它當(dāng)做裝飾器使用的例子:
from unittest.mock import patch import example @patch('example.func') def test1(x, mock_func): example.func(x) # Uses patched example.func mock_func.assert_called_with(x)
它還可以被當(dāng)做一個(gè)上下文管理器:
with patch('example.func') as mock_func: example.func(x) # Uses patched example.func mock_func.assert_called_with(x)
最后,你還可以手動(dòng)的使用它打補(bǔ)丁:
p = patch('example.func') mock_func = p.start() example.func(x) mock_func.assert_called_with(x) p.stop()
如果可能的話,你能夠疊加裝飾器和上下文管理器來(lái)給多個(gè)對(duì)象打補(bǔ)丁。例如:
@patch('example.func1') @patch('example.func2') @patch('example.func3') def test1(mock1, mock2, mock3): ... def test2(): with patch('example.patch1') as mock1, \ patch('example.patch2') as mock2, \ patch('example.patch3') as mock3: ...
討論
patch()
接受一個(gè)已存在對(duì)象的全路徑名,將其替換為一個(gè)新的值。 原來(lái)的值會(huì)在裝飾器函數(shù)或上下文管理器完成后自動(dòng)恢復(fù)回來(lái)。 默認(rèn)情況下,所有值會(huì)被 MagicMock
實(shí)例替代。例如:
>>> x = 42 >>> with patch('__main__.x'): ... print(x) ... <MagicMock name='x' id='4314230032'> >>> x 42 >>>
不過(guò),你可以通過(guò)給 patch()
提供第二個(gè)參數(shù)來(lái)將值替換成任何你想要的:
>>> x 42 >>> with patch('__main__.x', 'patched_value'): ... print(x) ... patched_value >>> x 42 >>>
被用來(lái)作為替換值的 MagicMock
實(shí)例能夠模擬可調(diào)用對(duì)象和實(shí)例。 他們記錄對(duì)象的使用信息并允許你執(zhí)行斷言檢查,例如:
>>> from unittest.mock import MagicMock >>> m = MagicMock(return_value = 10) >>> m(1, 2, debug=True) 10 >>> m.assert_called_with(1, 2, debug=True) >>> m.assert_called_with(1, 2) Traceback (most recent call last): File "<stdin>", line 1, in <module> File ".../unittest/mock.py", line 726, in assert_called_with raise AssertionError(msg) AssertionError: Expected call: mock(1, 2) Actual call: mock(1, 2, debug=True) >>> >>> m.upper.return_value = 'HELLO' >>> m.upper('hello') 'HELLO' >>> assert m.upper.called >>> m.split.return_value = ['hello', 'world'] >>> m.split('hello world') ['hello', 'world'] >>> m.split.assert_called_with('hello world') >>> >>> m['blah'] <MagicMock name='mock.__getitem__()' id='4314412048'> >>> m.__getitem__.called True >>> m.__getitem__.assert_called_with('blah') >>>
一般來(lái)講,這些操作會(huì)在一個(gè)單元測(cè)試中完成。例如,假設(shè)你已經(jīng)有了像下面這樣的函數(shù):
# example.py from urllib.request import urlopen import csv def dowprices(): u = urlopen('http://finance.yahoo.com/d/quotes.csv?s=@^DJI&f=sl1') lines = (line.decode('utf-8') for line in u) rows = (row for row in csv.reader(lines) if len(row) == 2) prices = { name:float(price) for name, price in rows } return prices
正常來(lái)講,這個(gè)函數(shù)會(huì)使用 urlopen()
從Web上面獲取數(shù)據(jù)并解析它。 在單元測(cè)試中,你可以給它一個(gè)預(yù)先定義好的數(shù)據(jù)集。下面是使用補(bǔ)丁操作的例子:
import unittest from unittest.mock import patch import io import example sample_data = io.BytesIO(b'''\ "IBM",91.1\r "AA",13.25\r "MSFT",27.72\r \r ''') class Tests(unittest.TestCase): @patch('example.urlopen', return_value=sample_data) def test_dowprices(self, mock_urlopen): p = example.dowprices() self.assertTrue(mock_urlopen.called) self.assertEqual(p, {'IBM': 91.1, 'AA': 13.25, 'MSFT' : 27.72}) if __name__ == '__main__': unittest.main()
本例中,位于 example
模塊中的 urlopen()
函數(shù)被一個(gè)模擬對(duì)象替代, 該對(duì)象會(huì)返回一個(gè)包含測(cè)試數(shù)據(jù)的 ByteIO()
還有一點(diǎn),在打補(bǔ)丁時(shí)我們使用了 example.urlopen
來(lái)代替 urllib.request.urlopen
。 當(dāng)你創(chuàng)建補(bǔ)丁的時(shí)候,你必須使用它們?cè)跍y(cè)試代碼中的名稱。 由于測(cè)試代碼使用了 from urllib.request import urlopen
,那么 dowprices()
函數(shù) 中使用的 urlopen()
函數(shù)實(shí)際上就位于 example
模塊了。
本節(jié)實(shí)際上只是對(duì) unittest.mock
模塊的一次淺嘗輒止。 更多更高級(jí)的特性,請(qǐng)參考 官方文檔
以上就是Python如何在單元測(cè)試中給對(duì)象打補(bǔ)丁的詳細(xì)內(nèi)容,更多關(guān)于Python 單元測(cè)試的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- python單元測(cè)試框架pytest的使用示例
- Python編寫(xiě)單元測(cè)試代碼實(shí)例
- Python單元測(cè)試及unittest框架用法實(shí)例解析
- Python unittest單元測(cè)試框架實(shí)現(xiàn)參數(shù)化
- Python unittest單元測(cè)試框架及斷言方法
- Python單元測(cè)試與測(cè)試用例簡(jiǎn)析
- Python 單元測(cè)試(unittest)的使用小結(jié)
- Python unittest單元測(cè)試框架總結(jié)
- Python unittest單元測(cè)試框架的使用
- 全面介紹python中很常用的單元測(cè)試框架unitest
相關(guān)文章
計(jì)算機(jī)二級(jí)python學(xué)習(xí)教程(2) python語(yǔ)言基本語(yǔ)法元素
這篇文章主要為大家詳細(xì)介紹了計(jì)算機(jī)二級(jí)python學(xué)習(xí)教程的第2篇,Python語(yǔ)言基本語(yǔ)法元素,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-05-05python cx_Oracle模塊的安裝和使用詳細(xì)介紹
這篇文章主要介紹了python cx_Oracle模塊的安裝和使用詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下2017-02-02python隨機(jī)生成庫(kù)faker庫(kù)api實(shí)例詳解
今天小編就為大家分享一篇python隨機(jī)生成庫(kù)faker庫(kù)api實(shí)例詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11Keras保存模型并載入模型繼續(xù)訓(xùn)練的實(shí)現(xiàn)
這篇文章主要介紹了Keras保存模型并載入模型繼續(xù)訓(xùn)練的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02Python學(xué)習(xí)筆記之open()函數(shù)打開(kāi)文件路徑報(bào)錯(cuò)問(wèn)題
這篇文章主要介紹了Python學(xué)習(xí)筆記之open()函數(shù)打開(kāi)文件路徑報(bào)錯(cuò)問(wèn)題,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04Python3中對(duì)json格式數(shù)據(jù)的分析處理
這篇文章主要介紹了Python3中對(duì)json格式數(shù)據(jù)的分析處理,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01Python3.5 + sklearn利用SVM自動(dòng)識(shí)別字母驗(yàn)證碼方法示例
這篇文章主要給大家介紹了關(guān)于Python3.5 + sklearn利用SVM自動(dòng)識(shí)別字母驗(yàn)證碼的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Python具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05