如何检查模拟函数是否已被调用?

时间:2019-09-24 11:34:11

标签: python python-3.x pytest

我正在为一个简单的函数编写单元测试,该函数将字节写入s3:

import s3fs

def write_bytes_as_csv_to_s3(payload, bucket, key):
    fs = s3fs.S3FileSystem()
    fname = f"{bucket}/{key}"
    print(f"writing {len(payload)} bytes to {fname}")
    with fs.open(fname, "wb") as f:
        f.write(payload)
    return fname


def test_write_bytes_as_csv_to_s3(mocker):
    s3fs_mock = mocker.patch('s3fs.S3FileSystem')
    open_mock = mocker.MagicMock()
    # write_mock = mocker.MagicMock()
    # open_mock.write.return_value = write_mock
    s3fs_mock.open.invoke.return_value = open_mock
    result = write_bytes_as_csv_to_s3('awesome'.encode(), 'random', 'key')
    assert result == 'random/key'
    s3fs_mock.assert_called_once()
    open_mock.assert_called_once()
    # write_mock.assert_called_once()

如何检查方法openwrite是否已被调用一次?不确定如何设置mocker来解决我的情况。

2 个答案:

答案 0 :(得分:0)

您上面编写的单元测试非常完美,并且涵盖了您要测试的方法的所有功能。

在pytest中,有一项功能可以获取unittest覆盖率报告,该报告将显示unittest覆盖的行。

请安装pytest插件html-report(如果未安装)并执行以下文档:-

py.test --cov=<filename to cover: unittest> --cov-report=html <testfile>

之后,您可能会在 htmlconv /目录的当前位置 o / r中找到一个html文件。然后,您可以轻松地了解覆盖的范围以及单元测试覆盖率的百分比。

答案 1 :(得分:0)

问题在于了解每个模拟的创建方式以及模拟的内容。例如,mocker.patch('s3fs.S3FileSystem')返回s3fs.S3FileSystem的模拟,而不是调用s3fs.S3FileSystem()返回的实例。然后要模拟with fs.open(fname, "wb") as f,您需要模拟__enter__ dunder方法返回的内容。希望下面的代码可以使关系清楚:

def test_write_bytes_as_csv_to_s3(mocker):
    # Mock of the open's context manager
    open_cm_mock = mocker.MagicMock()

    # Mock of the object returned by fs.open()
    open_mock = mocker.MagicMock()
    open_mock.__enter__.return_value = open_cm_mock

    # Mock of the new instance returned by s3fs.S3FileSystem()
    fs_mock = mocker.MagicMock()
    fs_mock.open.return_value = open_mock

    # Patching of s3fs.S3FileSystem 
    mocker.patch('s3fs.S3FileSystem').return_value = fs_mock

    # Running the tested code and making assertions
    result = write_bytes_as_csv_to_s3('awesome'.encode(), 'random', 'key')

    assert result == 'random/key'
    assert open_cm_mock.write.call_count == 1