我在测试读取文件第一行的函数时遇到问题,并在文件路径不存在时引发
Exception
。
当前代码:
from unittest.mock import patch, mock_open
from pytest import raises
from os.path import exists
def read_from_file(file_path):
if not exists(file_path):
raise Exception("File does not exists!")
with open(file_path, "r") as f:
return f.read().splitlines()[0]
@patch("builtins.open", new_callable=mock_open, read_data="Correct string\nWrong string\nWrong string")
@patch("os.path.exists", return_value=True)
def test_read_file_and_returns_the_correct_string_with_multiple_lines(mock_os, mock_file):
result = read_from_file("xyz")
mock_file.assert_called_once_with("xyz", "r")
assert result == "Correct string"
@patch("builtins.open", new_callable=mock_open, read_data="Correct string")
@patch("os.path.exists", return_value=False)
def test_throws_exception_when_file_doesnt_exist(mock_os, mock_file):
with raises(Exception):
read_from_file("xyz")
装饰器
@patch("os.path.exists", return_value=True)
和@patch("os.path.exists", return_value=False)
在这两个测试中似乎都没有效果。
如何模拟文件的存在?
您面临的问题与
@patch
装饰器的顺序有关。装饰器是从最内层到最外层应用的。因此,在您的测试中, mock_file
参数对应于 builtins.open
,而 mock_os
参数对应于 os.path.exists
。
当您模拟多个对象时,模拟的对象将按照补丁装饰器出现的顺序传递给测试函数。在您的情况下,您应该切换函数签名中模拟参数的顺序以匹配装饰器。
from unittest.mock import patch, mock_open
from pytest import raises
from os.path import exists
def read_from_file(file_path):
if not exists(file_path):
raise Exception("File does not exists!")
with open(file_path, "r") as f:
return f.read().splitlines()[0]
@patch("os.path.exists", return_value=True)
@patch("builtins.open", new_callable=mock_open, read_data="Correct string\nWrong string\nWrong string")
def test_read_file_and_returns_the_correct_string_with_multiple_lines(mock_file, mock_os):
result = read_from_file("xyz")
mock_file.assert_called_once_with("xyz", "r")
assert result == "Correct string"
@patch("os.path.exists", return_value=False)
@patch("builtins.open", new_callable=mock_open, read_data="Correct string")
def test_throws_exception_when_file_doesnt_exist(mock_file, mock_os):
with raises(Exception):
read_from_file("xyz")