簡體   English   中英

如何使用Python Mock斷言接受序列參數的調用?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM