Skip to main content
 首页 » 编程设计

python之谁在 "don' t 模拟第 3 方”和 "ensure close() called"之间的战斗中获胜

2025年05月04日10daizhj

我有这段代码要进行单元测试:

@staticmethod 
def _read_from_zip(pkg_zip_path): 
    """ 
    Return a |BlobCollection| instance loaded from *pkg_zip_path*. 
    """ 
    blobs = BlobCollection() 
    zipf = ZipFile(pkg_zip_path) 
    for name in zipf.namelist(): 
        blobs[name] = zipf.read(name) 
    zipf.close() 
    root_uri = os.path.splitext(pkg_zip_path)[0] 
    return PhysPkg(blobs, root_uri) 

它调用 ZipFile,一个库/第三方包,所以我想编写一个与 ZipFile 集成的测试,而不是模拟它(不要模拟第 3 方代码规则)。

这是我目前的测试。 initializer_mock() 是一个辅助函数,用于修补类上的 __init__() 方法,在这种情况下为 PhysPkg:

from opcdiag.phys_pkg import PhysPkg 
 
MINI_PKG_PATH = 'test_files/mini_pkg.zip' 
 
@pytest.fixture 
def init(self, request): 
    return initializer_mock(PhysPkg, request) 
 
def it_can_construct_from_a_zip_package(self, init): 
    PhysPkg._read_from_zip(MINI_PKG_PATH) 
    expected_blobs = {'uri_1': b'blob_1\n', 'uri_2': b'blob_2\n'} 
    init.assert_called_once_with(expected_blobs, ROOT_URI) 

问题是,因为我没有模拟 ZipFile,所以我不知道如何测试调用了 close() 方法。

也许我应该写两个测试?一个是通过测试结果确保与 ZipFile 的正确集成,另一个是通过模拟 ZipFile 确保 close() 被调用?

请您参考如下方法:

是的,您应该编写 2 个测试。或者您可以为您的库创建一个代理,它转发每个方法,但计算 close 被调用的次数。

我使用 proxy 而不是 mock 是有原因的。您没有替换它(就像模拟对象通常做的那样)。您只是添加了一个透明层。

您“不模拟第 3 方库”的原因是您需要测试它们(尤其是当您更新它们或可能想要更新它们时)。一种选择是信任提供者。另一个是创建一个完整的测试。第三个(是的,由“不要模拟第 3 方库”提倡的那个)是仅在您的软件有效使用它们的那些方面测试它们。 proxy mock 不会改变这一点。