繁体   English   中英

如何编写 pytest 来测试在单个 function 中打开两个单独的文件

[英]How to write a pytest to test for opening two separate files in a single function

如何使用 pytest 检查同一 function 中的两个不同文件是否正确打开?

open_two_files.py

def open_two_files(input_filepath, output_filepath):
    open_output = open(output_filepath, 'w')
    with open(input_filepath, 'r') as open_input:
      for line in open_input:
        open_output.write('foo')

我用这个答案来建立一个测试

test_open_two_files.py

import pytest
from unittest.mock import patch, mock_open
from open_two_files import *


def test_open_two_files():
    open_mock = mock_open()
    with patch('open_two_files.open', open_mock, create=True):
        open_two_files("input_filepath", "output_filepath")
    open_mock.assert_called_with("input_filepath", 'r')
    # pytest passes with the following line commented out
    open_mock.assert_called_with("output_filepath", 'w')

我得到的错误是

E           AssertionError: expected call not found.
E           Expected: open('output_filepath', 'w')
E           Actual: open('input_filepath', 'r')

如果我注释掉最后一行,则测试通过。 测试似乎只查看文件最后一次打开的时间。 请问如何测试所有出现的文件被打开?

如果您查看assert_called_with文档,您将看到:

此方法是断言最后一次调用是以特定方式进行的便捷方式

(强调我的)

您可以使用assert_any_call来检查这些 arguments 的任何调用:

def test_open_two_files():
    open_mock = mock_open()
    with patch('open_two_files.open', open_mock, create=True):
        open_two_files("input_filepath", "output_filepath")
    assert open_mock.call_count == 2
    open_mock.assert_any_call("input_filepath", 'r')
    open_mock.assert_any_call("output_filepath", 'w')

如果您还想检查调用的顺序,则必须分别检查每个调用:

def test_open_two_files():
    ...
    assert open_mock.call_count == 2
    assert open_mock.call_args_list[0][0] == ("output_filepath", 'w')
    assert open_mock.call_args_list[1][0] == ("input_filepath", 'r')

或者,如果您至少在 Python 3.8 下:

def test_open_two_files():
    ...
    assert open_mock.call_count == 2
    assert open_mock.call_args_list[0].args == ("output_filepath", 'w')
    assert open_mock.call_args_list[1].args == ("input_filepath", 'r')

(调用 args 的argskwargs属性已在 Python 3.8 中引入)

我创建了一个开源 pytest 夹具来帮助我自动创建断言以在这种情况下节省一些时间。

如果您pip install pytest-mock-generator ,您将获得名为mg的模拟生成器夹具,可以像这样使用:

def test_open_two_files(mg):
    open_mock = mock_open()
    with patch('open_two_files.open', open_mock, create=True):
        open_two_files("input_filepath", "output_filepath")
    open_mock.assert_called_with("input_filepath", 'r')

    mg.generate_asserts(open_mock)

然后执行您的测试,夹具将打印到控制台,并将以下内容复制到剪贴板:

from mock import call

assert 2 == open_mock.call_count
open_mock.assert_has_calls(calls=[call('output_filepath', 'w'),call('input_filepath', 'r'),])
open_mock.return_value.__enter__.assert_called_once_with()
open_mock.return_value.__iter__.assert_called_once_with()
open_mock.return_value.__exit__.assert_called_once_with(None, None, None)

您可以将代码按原样插入到测试中,也可以根据需要对其进行修改。 假设您不关心测试上下文的进入和退出,您的最终测试将如下所示:

from unittest.mock import patch, mock_open, call
from open_two_files import *


def test_open_two_files():
    open_mock = mock_open()
    with patch('open_two_files.open', open_mock, create=True):
        open_two_files("input_filepath", "output_filepath")
    open_mock.assert_called_with("input_filepath", 'r')

    assert 2 == open_mock.call_count
    open_mock.assert_has_calls(calls=[call('output_filepath', 'w'),call('input_filepath', 'r'),])

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM