簡體   English   中英

如何使用生成器參數驗證 Python 模擬調用

[英]How to verify Python mock calls with generator argument

我有一個 function 以Iterable作為參數:

def print_me(vals: Iterable[str]) -> None:
    ...

它被一個生成器調用:

def run():
    print_me((str(i) for i in range(10)))

我想修補和模擬print_me()並驗證它是否被特定參數調用。 使用普通的舊列表,這很容易:

mock.assert_called_with(["0", "1", ...])

但是對於生成器,因為它不能相等或重放,所以這更棘手。

我找到了一些解決方案。 我可以手動捕獲參數,但如果多次調用該方法,它會變得更加混亂:

@patch('module.print_me')
def test(self, mock):
    captured = None
    mock.side_effect = lambda vals: captured = vals
    run()    
    mock.assert_called_once_with(mock.ANY)
    self.assertEqual(list(captured), ["0", "1", ...])

我也可以代理模擬。 這使得斷言干凈,但想想有點奇怪,並且每次實際函數的 arguments 更改時,都需要更新proxy() function。

@patch('module.print_me')
def test(self, proxy_mock):
    mock = mock.Mock()
    def proxy(vals):
        mock(list(vals))

    proxy_mock.side_effect = proxy

    run()    
    mock.assert_called_once_with(["0", "1"])
    mock.assert_called_once_with(["2", "3"])

還有 PyHamcrest。 Hamcrest 在 Java 測試中確實很受歡迎,但在 Python 中似乎並不受歡迎。 也就是說,它做了我想要的:

@patch('module.print_me')
def test(self, mock):
    run()
    mock.assert_called_once_with(match_equality(contains_exactly(["2", "3"])))

有一種更簡單的測試方法,那就是使用模擬 object 的call_args屬性。 call_args返回一個元組,其中第一項是args ,第二項是kwargs Python 3.8 中的語法略有更改,以允許通過執行mock_object.call_args.argsmock_object.call_args.kwargs訪問這些項目,但我在 Python 3.7 上運行它,所以我采用更過時的方法。

@patch("src.module.print_me")
def test_run(mock_print):
    run()
    args, _ = mock_print.call_args
    # grab the one and only call argument
    gen = args[0]
    expected = [str(i) for i in range(10)]
    
    assert list(gen) == expected

正如您在上面的代碼片段中看到的那樣,我們獲取輸入到我們的模擬 object 的參數,使用它,然后將其與預期值進行比較。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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