Python如何在單元測試中給物件打補丁

2022-09-28 08:42:11 字數 3647 閱讀 3806

問題

你寫的單元測試中需要給指定的物件打補丁, 用來斷言它們在測試中的期望行為(比如,斷言被呼叫時的引數個數,訪問指定的屬性等)。

解決方案

unittest.mock.patch()函式可被用來解決這個問題。patch()還可被用作乙個裝飾器、上下文管理器或單獨使用,儘管並不常見。 例如,下面是乙個將它當做裝飾器使用的例子:

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)

它還可以被當做乙個上下文管理器:

with patch('example.func') as mock_func:

example.func(x) # uses patched example.func

mock_func.assert_called_with(x)

最後,你還可以手動的使用它打補丁:

p = patch('example.func')

mock_func = p.start()

example.func(x)

mock_func.assert_called_with(x)

p.stop()

如果可能的話,你能夠疊加裝程式設計客棧飾器和上下文管理器來給多個物件打補丁。例如:

@patch('example.func1')

@patch('example.func2')

@patch('example.func3')

def test1(mock1, mock2, mockvteqd3):

...def test2():

with patch('example.patch1') as mock1, \

patch('example.patch2') as mock2, \

patch('example.patch3') as mock3:

...討論

patch()接受乙個已存在物件的全路徑名,將其替換為乙個新的值。 原來的值會在裝飾器函式或上下文管理器完成後自動恢復回來。 預設情況下,所有值會被magicmock例項替代。例如:

>>> x = 42

>>> with patch('__main__.x'):

... print(x)

...>>> x

42>>>

不過,你可以通過給patch()提供第二個引數來將值替換成任何你想要的:

>>> x

42>>> with patch('__main__.x', 'patched_value'):

... print(程式設計客棧x)

...patched_value

>>> x

42>>>

被用來作為替換值的magicmock例項能夠模擬可呼叫物件和例項。 他們記錄物件的使用資訊並允許你執行斷言檢查,例如:

>>> 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 "", line 1, in

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']

>>> m.__getitem__.called

true

>>> m.__getitem__.assert_called_with('blah')

>>>

一般來講,這些操作會在乙個單元測試中完成。例如,假設你已經有了像下面這樣的函式:

# example.py

from urllib.request import urlopen

import csv

def dowprices():

u = urlopen('')

lines = (line.decode('utf-8') for line in u)

rows = (row for row in csv.reader(lines) if len(row) == 2)

prices =

return prices

正常來講,這個函式會使用urlopen()從web上面獲取資料並解析它。 在單元測試中,你可以給它乙個預先定義好的資料集。下面是使用補丁操作的例子:

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,

)if __name__ == '__main__':

unittest.main()

本例中,位於example模組中的urlopen()函式被乙個模擬物件替代, 該物件會返回乙個包含測試資料的byteio()

還有一點,在打補丁時我們使用了example.urlopen來代替urllib.request.urlopen。 當你建立補丁的時候,你必須使用它們在測試**中的名稱。 由於測試**使用了from urllib.request import urlopen,那麼dowprices()函式 中使用的urlopen()函式實際上就位於example模組了。

如何在前端應用中實現單元測試

前端工程化是現代前端提公升效率和 質量的乙個重要手段。單元測試作為保障 質量,提公升 可維護性的一種方法,也越來越多的在前端得到應用。本文以前端主流的 vue 框架為基礎,帶領大家在前端應用中搭建單元測試,並演示如何對 vue 單檔案元件進行測試。希望通過本文的的講述,能給希望學習如何在前端應用中進...

Python 單元測試

一 假設我們編寫了一段程式,主要功能是完成阿拉伯數字和羅馬數字之間的轉換 在羅馬數字中,利用7個字母進行重複或者組合來表達各式各樣的數字 i 1 v 5 x 10 l 50 c 100 d 500 m 1000 還有一些關於構造羅馬數字的規則。此程式的框架如下 其中,class romanerror...

python 單元測試

assertequal a,b assertnotequal a,b 斷言值是否相等 assertis a,b assertisnot a,b 斷言是否同一物件 記憶體位址一樣 assertlistequal list1,list2 assertitemnotequal list1,list2 斷言...