![](/img/trans.png)
[英]Python - How can I assert a mock object was not called with specific arguments?
[英]How can I assert calls that accept sequence arguments with Python Mock?
我正在處理一系列用戶定義的對象。 它看起來類似於以下內容:
class Thing(object):
def __init__(self, x, y):
self.x = x
self.y = y
我目前正在測試的方法具有類似於以下的功能:
def my_function(things):
x_calc = calculate_something(t.x for t in things)
y_calc = calculate_something(t.y for t in things)
return x_calc / y_calc
我面臨的問題是測試對calculate_something
的調用。 我想斷言這些調用發生了,就像這樣:
calculateSomethingMock.assert_any_call(the_sequence)
我不關心傳遞給calculate_something
的序列的順序,但我確實關心元素都存在。 我可以在調用set
包裝生成器函數,但我不覺得我的測試應該指示將什么類型的序列傳遞給calculate_something
。 我應該能夠以任何順序傳遞它。 我也可以創建一個生成序列的方法,而不是使用生成器語法並模擬該方法,但這似乎有點過分。
我怎樣才能最好地構建這個斷言,或者我在這里測試是否存在結構不良的代碼?
我使用Python 2.7.3與Mock 1.0.1。
(對於那些覺得有必要發表評論的人,我知道我最后一次做測試,這不是最好的做法。)
編輯:
在觀看了這個名為“為什么你沒有得到格雷戈里·莫克的模擬對象”的精彩演講后,我重新考慮過我是否應該嘲笑calculate_something
方法。
查看Mock文檔,有一個call_args_list可以執行您想要的操作。
所以你會在你的測試中模擬出calculate_something
。
calculate_something = Mock(return_value=None)
my_function
完成后,您可以通過執行以下操作檢查傳遞的參數:
calculate_something.call_args_list
這將返回所有調用的列表(傳遞相應的元素)。
編輯 :
(對不起,我花了這么長時間,我不得不在我的機器上安裝Python3.3)
mymodule.py
class Thing:
...
def calculate_something:
...
def my_function(things):
# Create the list outside in order to avoid a generator object
# from being passed to the Mock object.
xs = [t.x for t in things]
x_calc = calculate_something(xs)
ys = [t.y for t in things]
y_calc = calculate_something(ys)
return True
test_file.py
import unittest
from unittest.mock import patch, call
import mymodule
class TestFoo(unittest.TestCase):
# You can patch calculate_something here or
# do so inside the test body with
# mymodule.calcualte_something = Mock()
@patch('mymodule.calculate_something')
def test_mock(self, mock_calculate):
things = [mymodule.Thing(3, 4), mymodule.Thing(7, 8)]
mymodule.my_function(things)
# call_args_list returns [call([3, 7]), call([4, 8])]
callresult = mock_calculate.call_args_list
# Create our own call() objects to compare against
xargs = call([3, 7])
yargs = call([4, 8])
self.assertEqual(callresult, [xargs, yargs])
# or
# we can extract the call() info
# http://www.voidspace.org.uk/python/mock/helpers.html#mock.call.call_list
xargs, _ = callresult[0]
yargs, _ = callresult[1]
xexpected = [3, 7]
yexpected = [4, 8]
self.assertEqual(xargs[0], xexpected)
self.assertEqual(yargs[0], yexpected)
if __name__ == '__main__':
unittest.main()
我沒有觸及我最初使用的代碼,但我一直在重新考慮我的測試方法。 我一直在努力更加小心我做什么,不要嘲笑。 我最近意識到我無意識地開始遵循這個經驗法則:如果它使我的測試變得更短更簡單,那就嘲笑它,如果它使測試變得更復雜則不管它。 在這種方法的情況下,簡單的輸入/輸出測試就足夠了。 沒有外部依賴項,如數據庫或文件。 所以簡而言之,我認為我的問題的答案是,“我不應該模擬calculate_something
。” 這樣做會使我的測試更難以閱讀和維護。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.