测试多个文件的功能
Testing function taking multiple files
我有一个函数需要 3 个文件和 returns 一个包含文件数据的元组。
例如:
第一个文件:
SVF2018-05-24_12:02:58.917
NHR2018-05-24_12:02:49.914
第二个文件:
SVF2018-05-24_1:04:11.332
NHR2018-05-24_1:04:02.979
第三个文件:
SVF_Sebastian Vettel_FERRARI
NHR_Nico Hulkenberg_RENAULT
我得到这样的结果:
result = (
[('SVF', '2018-05-24_12:02:58.917'), ('NHR', '2018-05-24_12:02:49.914')],
[('SVF', '2018-05-24_1:04:11.332'), ('NHR', '2018-05-24_1:04:02.979')],
[['SVF', 'Sebastian Vettel', 'FERRARI'], ['NHR', 'Nico Hulkenberg', 'RENAULT']]
)
函数本身如下所示:
def read_files(start_log, end_log, abbr) -> tuple:
"""
Takes two .log files - start and end, and a file containing abbreviation explanations.
Processes the data from the files and returns a tuple of lists containing lines for each file.
"""
for argument in [start_log, end_log, abbr]:
if not os.path.isfile(argument):
raise FileNotFoundError('Attribute must be a file.')
with open(argument, 'r') as f:
if argument == abbr:
abbr_lines = [line.strip().split('_') for line in f]
elif argument == start_log:
start_lines = [(line[:3], line.strip()[3:]) for line in f]
start_lines.pop()
else:
end_lines = [(line[:3], line.strip()[3:]) for line in f]
return start_lines, end_lines, abbr_lines
我需要为它写一个测试。
我没遇到错误:
class ReadFilesTestCase(unittest.TestCase):
def test_file_not_found_error(self):
with self.assertRaises(FileNotFoundError):
read_files('a.txt', 'b.txt', 'c.txt')
但我真的很难模拟多个文件作为函数的参数。
我一直在尝试这样做:
class ReadFilesTestCase(unittest.TestCase):
def setUp(self):
self.file_1 = mock.patch("builtins.open", mock.mock_open(read_data=self.file_1_data))
self.file_2 = mock.patch("builtins.open", mock.mock_open(read_data=self.file_1_data))
self.file_3 = mock.patch("builtins.open", mock.mock_open(read_data=self.file_1_data))
def test_read_files:
self.assertEqual(read_files(self.file_1, self.file_2, self.file_3), self.result)
但是我遇到了 FileNotFoundError。我也试过 @mock.patch.multiple - 效果不佳。
我想知道是否可以模拟文件,所以我就这样写:
self.assertEqual(read_files(fake_file_1, fake_file_2, fake_file_3), self.result)
我应该使用什么技术?我很感激任何建议。
这里的问题是使用 mock_open
你只能为所有文件名伪造 open
,而不是特定文件名。
我在这里看到两种可能性:使用 open
来模拟 open
而不是使用 open_mock
使用 side_effect
(有点难看,并且与实现紧密耦合),或者使用类似 pyfakefs
模拟文件系统(不那么丑,但重量级)。
第一种方法看起来像这样:
class ReadFilesTestCase(unittest.TestCase):
@mock.patch("os.path.isfile", return_value=True)
def test_read_files(self, mocked_isfile):
# as we have to mock the for look in the open file,
# we need to provide the lines as arrays (this will probably go in setUp)
file1_lines = ["SVF2018-05-24_12:02:58.917",
"NHR2018-05-24_12:02:49.914"]
file2_lines = ["SVF2018-05-24_1:04:11.332",
"NHR2018-05-24_1:04:02.979"]
file3_lines = ["SVF_Sebastian Vettel_FERRARI",
"NHR_Nico Hulkenberg_RENAULT"]
open_mock = MagicMock(name='open', spec=open)
# we have to first mock __enter__ to account for context manager
# then we use side_effect to define the result subsequent calls to open()
open_mock.return_value.__enter__.side_effect = [
file1_lines, file2_lines, file3_lines
]
with mock.patch('builtins.open', open_mock):
# the file names don't matter in this case
assert read_files("f1", "f2", "f3") == expected_result
对于第二种方法,你需要pyfakefs:
from pyfakefs import fake_filesystem_unittest
class ReadFilesTestCase(fake_filesystem_unittest.TestCase):
def setUp(self):
self.setUpPyfakefs()
def test_read_files(self, mocked_isfile):
# we create the needed files in the fake filesystem
self.fs.create_file("a.txt",
contents="SVF2018-05-24_12:02:58.917\nNHR2018-05-24_12:02:49.914")
self.fs.create_file("b.txt",
contents="SVF2018-05-24_1:04:11.332\nNHR2018-05-24_1:04:02.979")
self.fs.create_file("c.txt",
contents="SVF_Sebastian Vettel_FERRARI\nNHR_Nico Hulkenberg_RENAULT")
# now the files exist in the fake filesystem (e.g. in memory), and you can just use them
assert read_files("a.txt", "b.txt", "c.txt") == expected_result
免责声明:我是 pyfakefs 的贡献者。
我有一个函数需要 3 个文件和 returns 一个包含文件数据的元组。 例如:
第一个文件:
SVF2018-05-24_12:02:58.917
NHR2018-05-24_12:02:49.914
第二个文件:
SVF2018-05-24_1:04:11.332
NHR2018-05-24_1:04:02.979
第三个文件:
SVF_Sebastian Vettel_FERRARI
NHR_Nico Hulkenberg_RENAULT
我得到这样的结果:
result = (
[('SVF', '2018-05-24_12:02:58.917'), ('NHR', '2018-05-24_12:02:49.914')],
[('SVF', '2018-05-24_1:04:11.332'), ('NHR', '2018-05-24_1:04:02.979')],
[['SVF', 'Sebastian Vettel', 'FERRARI'], ['NHR', 'Nico Hulkenberg', 'RENAULT']]
)
函数本身如下所示:
def read_files(start_log, end_log, abbr) -> tuple:
"""
Takes two .log files - start and end, and a file containing abbreviation explanations.
Processes the data from the files and returns a tuple of lists containing lines for each file.
"""
for argument in [start_log, end_log, abbr]:
if not os.path.isfile(argument):
raise FileNotFoundError('Attribute must be a file.')
with open(argument, 'r') as f:
if argument == abbr:
abbr_lines = [line.strip().split('_') for line in f]
elif argument == start_log:
start_lines = [(line[:3], line.strip()[3:]) for line in f]
start_lines.pop()
else:
end_lines = [(line[:3], line.strip()[3:]) for line in f]
return start_lines, end_lines, abbr_lines
我需要为它写一个测试。
我没遇到错误:
class ReadFilesTestCase(unittest.TestCase):
def test_file_not_found_error(self):
with self.assertRaises(FileNotFoundError):
read_files('a.txt', 'b.txt', 'c.txt')
但我真的很难模拟多个文件作为函数的参数。
我一直在尝试这样做:
class ReadFilesTestCase(unittest.TestCase):
def setUp(self):
self.file_1 = mock.patch("builtins.open", mock.mock_open(read_data=self.file_1_data))
self.file_2 = mock.patch("builtins.open", mock.mock_open(read_data=self.file_1_data))
self.file_3 = mock.patch("builtins.open", mock.mock_open(read_data=self.file_1_data))
def test_read_files:
self.assertEqual(read_files(self.file_1, self.file_2, self.file_3), self.result)
但是我遇到了 FileNotFoundError。我也试过 @mock.patch.multiple - 效果不佳。
我想知道是否可以模拟文件,所以我就这样写:
self.assertEqual(read_files(fake_file_1, fake_file_2, fake_file_3), self.result)
我应该使用什么技术?我很感激任何建议。
这里的问题是使用 mock_open
你只能为所有文件名伪造 open
,而不是特定文件名。
我在这里看到两种可能性:使用 open
来模拟 open
而不是使用 open_mock
使用 side_effect
(有点难看,并且与实现紧密耦合),或者使用类似 pyfakefs
模拟文件系统(不那么丑,但重量级)。
第一种方法看起来像这样:
class ReadFilesTestCase(unittest.TestCase):
@mock.patch("os.path.isfile", return_value=True)
def test_read_files(self, mocked_isfile):
# as we have to mock the for look in the open file,
# we need to provide the lines as arrays (this will probably go in setUp)
file1_lines = ["SVF2018-05-24_12:02:58.917",
"NHR2018-05-24_12:02:49.914"]
file2_lines = ["SVF2018-05-24_1:04:11.332",
"NHR2018-05-24_1:04:02.979"]
file3_lines = ["SVF_Sebastian Vettel_FERRARI",
"NHR_Nico Hulkenberg_RENAULT"]
open_mock = MagicMock(name='open', spec=open)
# we have to first mock __enter__ to account for context manager
# then we use side_effect to define the result subsequent calls to open()
open_mock.return_value.__enter__.side_effect = [
file1_lines, file2_lines, file3_lines
]
with mock.patch('builtins.open', open_mock):
# the file names don't matter in this case
assert read_files("f1", "f2", "f3") == expected_result
对于第二种方法,你需要pyfakefs:
from pyfakefs import fake_filesystem_unittest
class ReadFilesTestCase(fake_filesystem_unittest.TestCase):
def setUp(self):
self.setUpPyfakefs()
def test_read_files(self, mocked_isfile):
# we create the needed files in the fake filesystem
self.fs.create_file("a.txt",
contents="SVF2018-05-24_12:02:58.917\nNHR2018-05-24_12:02:49.914")
self.fs.create_file("b.txt",
contents="SVF2018-05-24_1:04:11.332\nNHR2018-05-24_1:04:02.979")
self.fs.create_file("c.txt",
contents="SVF_Sebastian Vettel_FERRARI\nNHR_Nico Hulkenberg_RENAULT")
# now the files exist in the fake filesystem (e.g. in memory), and you can just use them
assert read_files("a.txt", "b.txt", "c.txt") == expected_result
免责声明:我是 pyfakefs 的贡献者。