新聞中心
unittest.mock —- 上手指南
3.3 新版功能.

我們提供的服務(wù)有:做網(wǎng)站、成都網(wǎng)站建設(shè)、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、水城ssl等。為超過千家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的水城網(wǎng)站制作公司
使用 mock
模擬方法調(diào)用
使用 Mock 的常見場景:
模擬函數(shù)調(diào)用
記錄在對象上的方法調(diào)用
你可能需要替換一個對象上的方法,用于確認(rèn)此方法被系統(tǒng)中的其他部分調(diào)用過,并且調(diào)用時使用了正確的參數(shù)。
>>> real = SomeClass()>>> real.method = MagicMock(name='method')>>> real.method(3, 4, 5, key='value')
使用了 mock (本例中的 real.method) 之后,它有方法和屬性可以讓你針對它是被如何使用的下斷言。
備注
在多數(shù)示例中,Mock 與 MagicMock 兩個類可以相互替換,而 MagicMock 是一個更適用的類,通常情況下,使用它就可以了。
如果 mock 被調(diào)用,它的 called 屬性就會變成 True,更重要的是,我們可以使用 assert_called_with() 或者 assert_called_once_with() 方法來確認(rèn)它在被調(diào)用時使用了正確的參數(shù)。
在如下的測試示例中,驗證對于 ProductionClass().method 的調(diào)用會導(dǎo)致 something 的調(diào)用。
>>> class ProductionClass:... def method(self):... self.something(1, 2, 3)... def something(self, a, b, c):... pass...>>> real = ProductionClass()>>> real.something = MagicMock()>>> real.method()>>> real.something.assert_called_once_with(1, 2, 3)
對象上的方法調(diào)用的 mock
上一個例子中我們直接在對象上給方法打補丁以檢查它是否被正確地調(diào)用。 另一個常見的用例是將一個對象傳給一個方法(或被測試系統(tǒng)的某個部分)然后檢查它是否以正確的方式被使用。
下面這個簡單的 ProductionClass 具有一個 closer 方法。 如果它附帶一個對象被調(diào)用那么它就會調(diào)用其中的 close。
>>> class ProductionClass:... def closer(self, something):... something.close()...
所以為了測試它我們需要傳入一個帶有 close 方法的對象并檢查它是否被正確地調(diào)用。
>>> real = ProductionClass()>>> mock = Mock()>>> real.closer(mock)>>> mock.close.assert_called_with()
我們不需要做任何事來在我們的 mock 上提供 ‘close’ 方法。 訪問 close 的操作就會創(chuàng)建它。 因此,如果 ‘close’ 還未被調(diào)用那么在測試時訪問它就將創(chuàng)建它,但是 assert_called_with() 則會引發(fā)一個失敗的異常。
模擬類
一個常見的用例是模擬被測試的代碼所實例化的類。 當(dāng)你給一個類打上補丁,該類就會被替換為一個 mock。 實例是通過 該用該類 來創(chuàng)建的。 這意味著你要通過查看被模擬類的返回值來訪問 “mock 實例”。
在下面的例子中我們有一個函數(shù) some_function 實例化了 Foo 并調(diào)用該實例中的一個方法。 對 patch() 的調(diào)用會將類 Foo 替換為一個 mock。 Foo 實例是調(diào)用該 mock 的結(jié)果,所以它是通過修改 return_value 來配置的。
>>> def some_function():... instance = module.Foo()... return instance.method()...>>> with patch('module.Foo') as mock:... instance = mock.return_value... instance.method.return_value = 'the result'... result = some_function()... assert result == 'the result'
命名你的 mock
給你的 mock 起個名字可能會很有用。 名字會顯示在 mock 的 repr 中并在 mock 出現(xiàn)于測試失敗消息中時可以幫助理解。 這個名字也會被傳播給 mock 的屬性或方法:
>>> mock = MagicMock(name='foo')>>> mock>>> mock.method
追蹤所有的調(diào)用
通常你會想要追蹤對某個方法的多次調(diào)用。 mock_calls 屬性記錄了所有對 mock 的子屬性的調(diào)用 —— 并且還包括對它們的子屬性的調(diào)用。
>>> mock = MagicMock()>>> mock.method()>>> mock.attribute.method(10, x=53)>>> mock.mock_calls[call.method(), call.attribute.method(10, x=53)]
如果你做了一個有關(guān) mock_calls 的斷言并且有任何非預(yù)期的方法被調(diào)用,則斷言將失敗。 這很有用處,因為除了斷言你所預(yù)期的調(diào)用已被執(zhí)行,你還會檢查它們是否以正確的順序被執(zhí)行并且沒有額外的調(diào)用:
你使用 call 對象來構(gòu)造列表以便與 mock_calls 進行比較:
>>> expected = [call.method(), call.attribute.method(10, x=53)]>>> mock.mock_calls == expectedTrue
然而,返回 mock 的調(diào)用的形參不會被記錄,這意味著不可能追蹤附帶了重要形參的創(chuàng)建上級對象的嵌套調(diào)用:
>>> m = Mock()>>> m.factory(important=True).deliver()>>> m.mock_calls[-1] == call.factory(important=False).deliver()True
設(shè)置返回值和屬性
在 mock 對象上設(shè)置返回值是非常容易的:
>>> mock = Mock()>>> mock.return_value = 3>>> mock()3
當(dāng)然你也可以對 mock 上的方法做同樣的操作:
>>> mock = Mock()>>> mock.method.return_value = 3>>> mock.method()3
返回值也可以在構(gòu)造器中設(shè)置:
>>> mock = Mock(return_value=3)>>> mock()3
如果你需要在你的 mock 上設(shè)置一個屬性,只需這樣做:
>>> mock = Mock()>>> mock.x = 3>>> mock.x3
有時你會想要模擬更復(fù)雜的情況,例如這個例子 mock.connection.cursor().execute("SELECT 1")。 如果我們希望這個調(diào)用返回一個列表,那么我們還必須配置嵌套調(diào)用的結(jié)果。
我們可以像這樣使用 call 在一個“鏈?zhǔn)秸{(diào)用”中構(gòu)造調(diào)用集合以便隨后方便地設(shè)置斷言:
>>> mock = Mock()>>> cursor = mock.connection.cursor.return_value>>> cursor.execute.return_value = ['foo']>>> mock.connection.cursor().execute("SELECT 1")['foo']>>> expected = call.connection.cursor().execute("SELECT 1").call_list()>>> mock.mock_calls[call.connection.cursor(), call.connection.cursor().execute('SELECT 1')]>>> mock.mock_calls == expectedTrue
對 .call_list() 的調(diào)用會將我們的調(diào)用對象轉(zhuǎn)成一個代表鏈?zhǔn)秸{(diào)用的調(diào)用列表。
通過 mock 引發(fā)異常
一個很有用的屬性是 side_effect。 如果你將該屬性設(shè)為一個異常類或者實例那么當(dāng) mock 被調(diào)用時該異常將會被引發(fā)。
>>> mock = Mock(side_effect=Exception('Boom!'))>>> mock()Traceback (most recent call last):...Exception: Boom!
附帶影響函數(shù)和可迭代對象
side_effect 也可以被設(shè)為一個函數(shù)或可迭代對象。 side_effect 作為可迭代對象的應(yīng)用場景適用于你的 mock 將要被多次調(diào)用,并且你希望每次調(diào)用都返回不同的值的情況。 當(dāng)你將 side_effect 設(shè)為一個可迭代對象時每次對 mock 的調(diào)用將返回可迭代對象的下一個值。
>>> mock = MagicMock(side_effect=[4, 5, 6])>>> mock()4>>> mock()5>>> mock()6
對于更高級的用例,例如根據(jù) mock 調(diào)用時附帶的參數(shù)動態(tài)改變返回值,side_effect 可以指定一個函數(shù)。 該函數(shù)將附帶與 mock 相同的參數(shù)被調(diào)用。 該函數(shù)所返回的就是調(diào)用所返回的對象:
>>> vals = {(1, 2): 1, (2, 3): 2}>>> def side_effect(*args):... return vals[args]...>>> mock = MagicMock(side_effect=side_effect)>>> mock(1, 2)1>>> mock(2, 3)2
模擬異步迭代器
從 python 3.8 起,AsyncMock 和 MagicMock 支持通過 __aiter__ 來模擬 異步迭代器。 __aiter__ 的 return_value 屬性可以被用來設(shè)置要用于迭代的返回值。
>>> mock = MagicMock() # AsyncMock also works here>>> mock.__aiter__.return_value = [1, 2, 3]>>> async def main():... return [i async for i in mock]...>>> asyncio.run(main())[1, 2, 3]
模擬異步上下文管理器
從 Python 3.8 起,AsyncMock 和 MagicMock 支持通過 __aenter__ 和 __aexit__ 來模擬 異步上下文管理器。 在默認(rèn)情況下,__aenter__ 和 __aexit__ 將為返回異步函數(shù)的 AsyncMock 實例。
>>> class AsyncContextManager:... async def __aenter__(self):... return self... async def __aexit__(self, exc_type, exc, tb):... pass...>>> mock_instance = MagicMock(AsyncContextManager()) # AsyncMock also works here>>> async def main():... async with mock_instance as result:... pass...>>> asyncio.run(main())>>> mock_instance.__aenter__.assert_awaited_once()>>> mock_instance.__aexit__.assert_awaited_once()
基于現(xiàn)有對象創(chuàng)建模擬對象
使用模擬操作的一個問題是它會將你的測試與你的 mock 實現(xiàn)相關(guān)聯(lián)而不是與你的真實代碼相關(guān)聯(lián)。 假設(shè)你有一個實現(xiàn)了 some_method 的類。 在對另一個類的測試中,你提供了一個 同樣 提供了 some_method 的模擬該對象的 mock 對象。 如果后來你重構(gòu)了第一個類,使得它不再具有 some_method —— 那么你的測試將繼續(xù)保持通過,盡管現(xiàn)在你的代碼已經(jīng)被破壞了!
Mock 允許你使用allows you to provide an object as a specification for the mock, using the spec 關(guān)鍵字參數(shù)來提供一個對象作為 mock 的規(guī)格說明。 在 mock 上訪問不存在于你的規(guī)格說明對象中的方法 / 屬性將立即引發(fā)一個屬性錯誤。 如果你修改你的規(guī)格說明的實現(xiàn),,那么使用了該類的測試將立即開始失敗而不需要你在這些測試中實例化該類。
>>> mock = Mock(spec=SomeClass)>>> mock.old_method()Traceback (most recent call last):...AttributeError: object has no attribute 'old_method'
使用規(guī)格說明還可以啟用對 mock 的調(diào)用的更聰明的匹配操作,無論是否有將某些形參作為位置或關(guān)鍵字參數(shù)傳入:
>>> def f(a, b, c): pass...>>> mock = Mock(spec=f)>>> mock(1, 2, 3)>>> mock.assert_called_with(a=1, b=2, c=3)
如果你想要讓這些更聰明的匹配操作也適用于 mock 上的方法調(diào)用,你可以使用 auto-speccing。
如果你想要更強形式的規(guī)格說明以防止設(shè)置任意屬性并獲取它們那么你可以使用 spec_set 來代替 spec。
補丁裝飾器
備注
在查找對象的名稱空間中修補對象使用 patch() 。使用起來很簡單,閱讀 補丁的位置 來快速上手。
測試中的一個常見需求是為類屬性或模塊屬性打補丁,例如修補內(nèi)置對象或修補某個模塊中的類來測試其是否被實例化。 模塊和類都可算是全局對象,因此對它們打補丁的操作必須在測試完成之后被還原否則補丁將持續(xù)影響其他測試并導(dǎo)致難以診斷的問題。
為此 mock 提供了三個便捷的裝飾器: patch(), patch.object() 和 patch.dict()。 patch 接受單個字符串,其形式 package.module.Class.attribute 指明你要修補的屬性。 它還可選擇接受一個值用來替換指定的屬性(或者類對象等等)。 ‘patch.object’ 接受一個對象和你想要修補的屬性名稱,并可選擇接受要用作補丁的值。
patch.object:
>>> original = SomeClass.attribute>>> @patch.object(SomeClass, 'attribute', sentinel.attribute)... def test():... assert SomeClass.attribute == sentinel.attribute...>>> test()>>> assert SomeClass.attribute == original>>> @patch('package.module.attribute', sentinel.attribute)... def test():... from package.module import attribute... assert attribute is sentinel.attribute...>>> test()
如果你要給一個模塊 (包括 builtins) 打補丁則可使用 patch() 來代替 patch.object():
>>> mock = MagicMock(return_value=sentinel.file_handle)>>> with patch('builtins.open', mock):... handle = open('filename', 'r')...>>> mock.assert_called_with('filename', 'r')>>> assert handle == sentinel.file_handle, "incorrect file handle returned"
如有必要模塊名可以是“帶點號”的,其形式如 package.module:
>>> @patch('package.module.ClassName.attribute', sentinel.attribute)... def test():... from package.module import ClassName... assert ClassName.attribute == sentinel.attribute...>>> test()
一個良好的模式是實際地裝飾測試方法本身:
>>> class MyTest(unittest.TestCase):... @patch.object(SomeClass, 'attribute', sentinel.attribute)... def test_something(self):... self.assertEqual(SomeClass.attribute, sentinel.attribute)...>>> original = SomeClass.attribute>>> MyTest('test_something').test_something()>>> assert SomeClass.attribute == original
如果你想要通過 Mock 來打補丁,你可以只附帶一個參數(shù)使用 patch() (或附帶兩個參數(shù)使用 patch.object())。 這將為你創(chuàng)建 mock 并傳遞給測試函數(shù) / 方法:
>>> class MyTest(unittest.TestCase):... @patch.object(SomeClass, 'static_method')... def test_something(self, mock_method):... SomeClass.static_method()... mock_method.assert_called_with()...>>> MyTest('test_something').test_something()
你可以使用以下模式來堆疊多個補丁裝飾器:
>>> class MyTest(unittest.TestCase):... @patch('package.module.ClassName1')... @patch('package.module.ClassName2')... def test_something(self, MockClass2, MockClass1):... self.assertIs(package.module.ClassName1, MockClass1)... self.assertIs(package.module.ClassName2, MockClass2)...>>> MyTest('test_something').test_something()
當(dāng)你嵌套 patch 裝飾器時將以它們被應(yīng)用的相同順序(即 Python 應(yīng)用裝飾器的正常順序)將 mock 傳入被裝飾的函數(shù)。 也就是說從下往上,因此在上面的示例中 test_module.ClassName2 的 mock 會被最先傳入。
還有一個 patch.dict() 用于在一定范圍內(nèi)設(shè)置字典中的值,并在測試結(jié)束時將字典恢復(fù)為其原始狀態(tài):
>>> foo = {'key': 'value'}>>> original = foo.copy()>>> with patch.dict(foo, {'newkey': 'newvalue'}, clear=True):... assert foo == {'newkey': 'newvalue'}...>>> assert foo == original
patch, patch.object 和 patch.dict 都可被用作上下文管理器。
在你使用 patch() 為你創(chuàng)建 mock 時,你可以使用 with 語句的 “as” 形式來獲得對 mock 的引用:
>>> class ProductionClass:... def method(self):... pass...>>> with patch.object(ProductionClass, 'method') as mock_method:... mock_method.return_value = None... real = ProductionClass()... real.method(1, 2, 3)...>>> mock_method.assert_called_with(1, 2, 3)
作為替代 patch, patch.object 和 patch.dict 可以被用作類裝飾器。 當(dāng)以此方式使用時其效果與將裝飾器單獨應(yīng)用到每個以 “test” 打頭的方法上相同。
更多示例
下面是一些針對更為高級應(yīng)用場景的補充示例。
模擬鏈?zhǔn)秸{(diào)用
實際上一旦你理解了 return_value 屬性那么使用 mock 模擬鏈?zhǔn)秸{(diào)用就會相當(dāng)直觀。 當(dāng)一個 mock 首次被調(diào)用,或者當(dāng)你在它被調(diào)用前獲取其 return_value 時,將會創(chuàng)建一個新的 Mock。
這意味著你可以通過檢視 return_value mock 來了解從調(diào)用被模擬對象返回的對象是如何被使用的:
>>> mock = Mock()>>> mock().foo(a=2, b=3)>>> mock.return_value.foo.assert_called_with(a=2, b=3)
從這里開始只需一個步驟即可配置并創(chuàng)建有關(guān)鏈?zhǔn)秸{(diào)用的斷言。 當(dāng)然還有另一種選擇是首先以更易于測試的方式來編寫你的代碼…
因此,如果我們有這樣一些代碼:
>>> class Something:... def __init__(self):... self.backend = BackendProvider()... def method(self):... response = self.backend.get_endpoint('foobar').create_call('spam', 'eggs').start_call()... # more code
假定 BackendProvider 已經(jīng)過良好測試,我們要如何測試 method()? 特別地,我們希望測試代碼段 # more code 是否以正確的方式使用了響應(yīng)對象。
由于這個鏈?zhǔn)秸{(diào)用來自一個實例屬性我們可以對 backend 屬性在 Something 實例上進行猴子式修補。 在這個特定情況下我們只對最后調(diào)用 start_call 的返回值感興趣所以我們不需要進行太多的配置。 讓我們假定它返回的是“文件類”對象,因此我們將確保我們的響應(yīng)對象使用內(nèi)置的 open() 作為其 spec。
為了做到這一點我們創(chuàng)建一個 mock 實例作為我們的 mock 后端并為它創(chuàng)建一個 mock 響應(yīng)對象。 要將該響應(yīng)對象設(shè)為最后的 start_call 的返回值我們可以這樣做:
mock_backend.get_endpoint.return_value.create_call.return_value.start_call.return_value = mock_response
我們可以通過更好一些的方式做到這一點,即使用 configure_mock() 方法直接為我們設(shè)置返回值:
>>> something = Something()>>> mock_response = Mock(spec=open)>>> mock_backend = Mock()>>> config = {'get_endpoint.return_value.create_call.return_value.start_call.return_value': mock_response}>>> mock_backend.configure_mock(**config)
有了這些我們就能準(zhǔn)備好給“mock 后端”打上猴子補丁并可以執(zhí)行真正的調(diào)用:
>>> something.backend = mock_backend>>> something.method()
使用 mock_calls 我們可以通過一個斷言來檢查鏈?zhǔn)秸{(diào)用。 一個鏈?zhǔn)秸{(diào)用就是在一行代碼中連續(xù)執(zhí)行多個調(diào)用,所以在 mock_calls 中將會有多個條目。 我們可以使用 call.call_list() 來為我們創(chuàng)建這個調(diào)用列表:
>>> chained = call.get_endpoint('foobar').create_call('spam', 'eggs').start_call()>>> call_list = chained.call_list()>>> assert mock_backend.mock_calls == call_list
部分模擬
在某些測試中我希望模擬對 datetime.date.today() 的調(diào)用以返回一個已知的日期,但我又不想阻止被測試的代碼創(chuàng)建新的日期對象。 很不幸 datetime.date 是用 C 語言編寫的,因此我不能簡單地給靜態(tài)的 date.today() 方法打上猴子補丁。
我找到了實現(xiàn)這一點的簡單方式即通過一個 mock 來實際包裝日期類,但通過對構(gòu)造器的調(diào)用傳遞給真實的類(并返回真實的實例)。
這里使用 patch 裝飾器 來模擬被測試模塊中的 date 類。 模擬 date 類中的 side_effect 屬性隨后被設(shè)為一個返回真實日期的 lambda 函數(shù)。 當(dāng)模擬 date 類被調(diào)用時將由 side_effect 構(gòu)造并返回一個真實日期。
>>> from datetime import date>>> with patch('mymodule.date') as mock_date:... mock_date.today.return_value = date(2010, 10, 8)... mock_date.side_effect = lambda *args, **kw: date(*args, **kw)...... assert mymodule.date.today() == date(2010, 10, 8)... assert mymodule.date(2009, 6, 8) == date(2009, 6, 8)
請注意我們沒有在全局范圍上修補 datetime.date,我們只是在 使用 它的模塊中給 date 打補丁。 參見 補丁的位置。
當(dāng) date.today() 被調(diào)用時將返回一個已知的日期,但對 date(...) 構(gòu)造器的調(diào)用仍會返回普通的日期。 如果不是這樣你會發(fā)現(xiàn)你必須使用與被測試的代碼完全相同的算法來計算出預(yù)期的結(jié)果,這是測試工作中的一個經(jīng)典的反模式。
對 date 構(gòu)造器的調(diào)用會被記錄在 mock_date 屬性中 (call_count 等),它們也可能對你的測試有用處。
有關(guān)處理模塊日期或其他內(nèi)置類的一種替代方式的討論請參見 這篇博客文章。
模擬生成器方法
Python 生成器是指在被迭代時使用 yield 語句來返回一系列值的函數(shù)或方法 1。
調(diào)用生成器方法 / 函數(shù)將返回生成器對象。 生成器對象隨后會被迭代。 迭代操作對應(yīng)的協(xié)議方法是 __iter__(),因此我們可以使用 MagicMock 來模擬它。
以下是一個使用 “iter” 方法模擬為生成器的示例類:
>>> class Foo:... def iter(self):... for i in [1, 2, 3]:... yield i...>>> foo = Foo()>>> list(foo.iter())[1, 2, 3]
我們要如何模擬這個類,特別是它的 “iter” 方法呢?
為了配置從迭代操作(隱含在對 list 的調(diào)用中)返回的值,我們需要配置調(diào)用 foo.iter() 所返回的對象。
>>> mock_foo = MagicMock()>>> mock_foo.iter.return_value = iter([1, 2, 3])>>> list(mock_foo.iter())[1, 2, 3]
1
此外還有生成器表達式和更多的生成器 進階用法,但在這里我們不去關(guān)心它們。 有關(guān)生成器及其強大功能的一個很好的介紹請參閱: 針對系統(tǒng)程序員的生成器妙招。
對每個測試方法應(yīng)用相同的補丁
If you want several patches in place for multiple test methods the obvious way is to apply the patch decorators to every method. This can feel like unnecessary repetition. Instead, you can use patch() (in all its various forms) as a class decorator. This applies the patches to all test methods on the class. A test method is identified by methods whose names start with test:
>>> @patch('mymodule.SomeClass')... class MyTest(unittest.TestCase):...... def test_one(self, MockSomeClass):... self.assertIs(mymodule.SomeClass, MockSomeClass)...... def test_two(self, MockSomeClass):... self.assertIs(mymodule.SomeClass, MockSomeClass)...... def not_a_test(self):... return 'something'...>>> MyTest('test_one').test_one()>>> MyTest('test_two').test_two()>>> MyTest('test_two').not_a_test()'something'
另一種管理補丁的方式是使用 補丁方法: start 和 stop。 它允許你將打補丁操作移至你的 setUp 和 tearDown 方法中。
>>> class MyTest(unittest.TestCase):... def setUp(self):... self.patcher = patch('mymodule.foo')... self.mock_foo = self.patcher.start()...... def test_foo(self):... self.assertIs(mymodule.foo, self.mock_foo)...... def tearDown(self):... self.patcher.stop()...>>> MyTest('test_foo').run()
如果你要使用這個技巧則你必須通過調(diào)用 stop 來確保補丁被“恢復(fù)”。 這可能要比你想像的更麻煩,因為如果在 setUp 中引發(fā)了異常那么 tearDown 將不會被調(diào)用。 unittest.TestCase.addCleanup() 可以做到更方便:
>>> class MyTest(unittest.TestCase):... def setUp(self):... patcher = patch('mymodule.foo')... self.addCleanup(patcher.stop)... self.mock_foo = patcher.start()...... def test_foo(self):... self.assertIs(mymodule.foo, self.mock_foo)...>>> MyTest('test_foo').run()
模擬未綁定方法
當(dāng)前在編寫測試時我需要修補一個 未綁定方法 (在類上而不是在實例上為方法打補丁)。 我需要將 self 作為第一個參數(shù)傳入因為我想對哪些對象在調(diào)用這個特定方法進行斷言。 問題是這里你不能用 mock 來打補丁,因為如果你用 mock 來替換一個未綁定方法那么當(dāng)從實例中獲取時它就不會成為一個已綁定方法,因而它不會獲得傳入的 self。 繞過此問題的辦法是改用一個真正的函數(shù)來修補未綁定方法。 patch() 裝飾器讓使用 mock 來給方法打補丁變得如此簡單以至于創(chuàng)建一個真正的函數(shù)成為一件麻煩事。
如果將 autospec=True 傳給 patch 那么它就會用一個 真正的 函數(shù)對象來打補丁。 這個函數(shù)對象具有與它所替換的函數(shù)相同的簽名,但會在內(nèi)部將操作委托給一個 mock。 你仍然可以通過與以前完全相同的方式來自動創(chuàng)建你的 mock。 但是這將意味著一件事,就是如果你用它來修補一個類上的非綁定方法那么如果它是從一個實例中獲取則被模擬的函數(shù)將被轉(zhuǎn)為已綁定方法。 傳給它的第一個參數(shù)將為 self,而這真是我想要的:
>>> class Foo:... def foo(self):... pass...>>> with patch.object(Foo, 'foo', autospec=True) as mock_foo:... mock_foo.return_value = 'foo'... foo = Foo()... foo.foo()...'foo'>>> mock_foo.assert_called_once_with(foo)
如果我們不使用 autospec=True 那么這個未綁定方法會改為通過一個 Mock 補丁來修補,而不是附帶 self 來調(diào)用。
通過 mock 檢查多次調(diào)用
mock 有一個很好的 API 用于針對你的 mock 對象如何被使用來下斷言。
>>> mock = Mock()>>> mock.foo_bar.
分享文章:創(chuàng)新互聯(lián)Python教程:unittest.mock —- 上手指南
網(wǎng)站URL:http://fisionsoft.com.cn/article/djghoeg.html


咨詢
建站咨詢
