簡體   English   中英

Python:斷言模擬 function 被調用了一個包含另一個字符串的字符串

[英]Python: Assert mock function was called with a string containing another string

這是我面臨的問題的簡化版本:假設我有一個 function 接受目錄路徑,然后刪除其所有內容,除了(可選)指定的“保留文件”,

import os

KEEP_FILE_CONSTANT = '.gitkeep'

def clear_directory(directory: str, retain: bool = True) -> bool:
    try:
        filelist = list(os.listdir(directory))
        for f in filelist:
            filename = os.path.basename(f)
            if retain and filename == KEEP_FILE_CONSTANT:
                continue
            os.remove(os.path.join(directory, f))
        return True
    except OSError as e:
        print(e)
        return False

我正在嘗試為此 function 編寫一個單元測試,以驗證調用了os.remove 這是目前我正在測試它的方式:

import pytest
from unittest.mock import ANY

@pytest.mark.parametrize('directory', [
     ('random_directory_1'),
     ('random_directory_2'),
     # ...
])
@patch('module.os.remove')
def test_clear_directory(delete_function, directory):
    clear_directory(directory)
    delete_function.assert_called()
    delete_function.assert_called_with(ANY)

理想情況下,我想在測試中斷言的是delete_function是使用包含directory的參數調用的,例如,

delete_function.assert_called_with(CONTAINS(directory)) 

或類似的東西。 我一直在查看PyHamcrest ,特別是contains_string function,但我不確定如何在此處應用它,或者是否可能。

有沒有辦法為這個用例實現一個 CONTAINS 匹配器?

這不是您問題的直接答案,但如果我正在編寫這些測試,我會采取不同的方法:

  • 創建一個臨時目錄。
  • 實際刪除文件。
  • 檢查是否只保留預期的文件。

這樣,您正在測試您想要的實際行為,而不是依賴於內部實現細節(即您使用os.remove()而不是Pathlib.unlink() () 之類的替代方法)。

如果您不熟悉,pytest 為此類測試提供了一個tmp_path夾具。 但是,填充臨時目錄仍然有點麻煩,尤其是如果您想測試各種嵌套文件層次結構。 不過,我編寫了一個名為tmp_files的夾具來簡化此操作,我認為它可能非常適合您的問題。 以下是測試的外觀:

import pytest

# I included tests for nested files, even though the sample function you
# provided doesn't support them, just to show how to do it.

@pytest.mark.parametrize(
    'tmp_files, to_remove, to_keep', [
        pytest.param(
            {'file.txt': ''},
            ['file.txt'],
            [],
            id='remove-1-file',
        ),
        pytest.param(
            {'file-1.txt': '', 'file-2.txt': ''},
            ['file-1.txt', 'file-2.txt'],
            [],
            id='remove-2-files',
        ),
        pytest.param(
            {'file.txt': '', 'dir/file.txt': ''},
            ['file.txt', 'dir/file.txt'],
            [],
            id='remove-nested-files',
            marks=pytest.mark.xfail,
        ),
        pytest.param(
            {'.gitkeep': ''},
            [],
            ['.gitkeep'],
            id='keep-1-file',
        ),
        pytest.param(
            {'.gitkeep': '', 'dir/.gitkeep': ''},
            [],
            ['.gitkeep', 'dir/.gitkeep'],
            id='keep-nested-files',
            marks=pytest.mark.xfail,
        ),
    ],
    indirect=['tmp_files'],
)
def test_clear_directory(tmp_files, to_remove, to_keep):
    clear_directory(tmp_files)

    for p in to_remove:
        assert not os.path.exists(tmp_files / p)
    for p in to_keep:
        assert os.path.exists(tmp_files / p)

簡單解釋一下, tmp_files參數指定要在每個臨時目錄中創建哪些文件,並且只是將文件名映射到文件內容的字典。 這里所有的文件都是簡單的文本文件,但也可以創建符號鏈接、FIFO 等indirect=['tmp_files']參數很容易忽略但非常重要。 它告訴 pytest 使用tmp_files參數對tmp_files夾具進行參數化。

暫無
暫無

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

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