如何在 Python 中模拟 os.listdir 来假装文件和目录?
问题描述
我有一个专有的存储库格式,我正在尝试开发一个 Python 模块来处理这些存储库.回购格式如下:
I have a proprietary repository format and I'm trying to develop a Python module to process these repositories. Repo format goes as:
/home/X/
|
+ alpha/
|
+ beta/
|
+ project.conf
这里,X
是一个项目.alpha
和 beta
是本项目中的文件夹,它们代表本项目中的组.group 是这个 repo 中的一个容器,它所代表的内容实际上与这个问题无关.repo X
在其根级别也有文件;project.conf
就是此类文件的一个示例.
Here, X
is a project. alpha
and beta
are folders inside this project and they represent groups in this project. A group is a container in this repo and what it represents is really not relevant for this question. The repo X
also has files in its root level; project.conf
is an example of such a file.
我有一个名为Project
的类,它抽象出X
等项目.Project
类有一个 load()
方法,用于构建内存中的表示.
I have a class called Project
that abstracts projects such as X
. The Project
class has a method load()
that builds an in-memory representation.
class Project(object):
def load(self):
for entry in os.listdir(self.root):
path = os.path.join(self.root, entry)
if os.path.isdir(path):
group = Group(path)
self.groups.append(group)
group.load()
else:
# process files ...
要通过模拟文件系统对 load()
方法进行单元测试,我有:
To unit test the load()
method by mocking the file system, I have:
import unittest
from unittest import mock
import Project
class TestRepo(unittest.TestCase):
def test_load_project(self):
project = Project("X")
with mock.patch('os.listdir') as mocked_listdir:
mocked_listdir.return_value = ['alpha', 'beta', 'project.conf']
project.load()
self.assertEqual(len(project.groups), 2)
这确实模拟了 os.listdir
成功.但我无法欺骗 Python 将 mocked_listdir.return_value
视为由文件和目录组成.
This does mock os.listdir
successfully. But I can't trick Python to treat mocked_listdir.return_value
as consisting of files and directories.
我如何模拟 os.listdir
或 os.path.isdir
,在同一个测试中,这样测试就会看到alpha
和 beta
作为目录,project.conf
作为文件?
How do I mock either os.listdir
or os.path.isdir
, in the same test, such that the test will see alpha
and beta
as directories and project.conf
as a file?
解决方案
我设法通过将一个可迭代对象传递给模拟的 isdir
的 side_effect
属性来实现所需的行为对象.
I managed to achieve the desired behavior by passing an iterable to the side_effect
attribute of the mocked isdir
object.
import unittest
from unittest import mock
import Project
class TestRepo(unittest.TestCase):
def test_load_project(self):
project = Project("X")
with mock.patch('os.listdir') as mocked_listdir:
with mock.patch('os.path.isdir') as mocked_isdir:
mocked_listdir.return_value = ['alpha', 'beta', 'project.conf']
mocked_isdir.side_effect = [True, True, False]
project.load()
self.assertEqual(len(project.groups), 2)
关键是 mocked_isdir.side_effect = [True, True, False]
行.可迭代对象中的布尔值应与传递给 mocked_listdir.return_value
属性的目录和文件条目的顺序相匹配.
The key is the mocked_isdir.side_effect = [True, True, False]
line. The boolean values in the iterable should match the order of directory and file entries passed to the mocked_listdir.return_value
attribute.
相关文章