Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Python单元测试中模拟文件系统?_Python_Unit Testing_Mocking_Filesystems - Fatal编程技术网

如何在Python单元测试中模拟文件系统?

如何在Python单元测试中模拟文件系统?,python,unit-testing,mocking,filesystems,Python,Unit Testing,Mocking,Filesystems,有没有标准的方法(不安装第三方库)在Python中进行跨平台文件系统模拟?如果我必须使用第三方库,那么哪个库是标准库?Python 3.3+中的标准模拟框架是;您可以将其用于文件系统或其他任何东西 您也可以通过猴子补丁进行模拟,简单地手动滚动: 一个简单的例子: import os.path os.path.isfile = lambda path: path == '/path/to/testfile' 更完整一点(未经测试): 在本例中,实际的mock很简单,但是您可以使用具有状态的东西来

有没有标准的方法(不安装第三方库)在Python中进行跨平台文件系统模拟?如果我必须使用第三方库,那么哪个库是标准库?

Python 3.3+中的标准模拟框架是;您可以将其用于文件系统或其他任何东西

您也可以通过猴子补丁进行模拟,简单地手动滚动:

一个简单的例子:

import os.path
os.path.isfile = lambda path: path == '/path/to/testfile'
更完整一点(未经测试):

在本例中,实际的mock很简单,但是您可以使用具有状态的东西来支持它们,以便能够表示文件系统操作,例如save和delete。是的,这有点难看,因为它需要在代码中复制/模拟基本文件系统

请注意,不能对python内置代码进行修补。话虽如此

对于早期版本,如果可能的话,使用第三方库,我会使用Michael Foord的Aweasome,它现在是标准库中的
unittest.mock
,从3.3+开始,多亏了,您可以在Python 2.5+上使用它。而且,它可以模仿内置的东西

()做你想做的事–一个假的文件系统;这是第三方,尽管那个方是谷歌。有关使用的讨论,请参阅

对于模拟,是Python 3.3+()的标准库;有关早期版本,请参见(对于Python 2.5+)

测试和模拟中的术语不一致;使用Gerard Meszaros的术语,您要求的是一个“假文件”:行为类似于文件系统(您可以创建、打开和删除文件),但不是实际的文件系统(在本例中,它位于内存中),因此您不需要测试文件或临时目录

import os
def test_create_file(tmpdir):
    p = tmpdir.mkdir("sub").join("hello.txt")
    p.write("content")
    assert p.read() == "content"
    assert len(tmpdir.listdir()) == 1
在经典的模拟中,您将模拟系统调用(在Python中,模拟
os
模块中的函数,如
os.rm
os.listdir
),但这要复杂得多。

正在获得大量的吸引力,并且它可以使用and(模拟)完成所有这一切

您可以使用
tmpdir
函数参数,该参数将提供测试调用特有的临时目录,该临时目录在基本临时目录中创建(默认情况下创建为系统临时目录的子目录)

monkeypatch
函数参数帮助您安全地设置/删除属性、字典项或环境变量,或修改导入的
sys.path

import os
def test_some_interaction(monkeypatch):
    monkeypatch.setattr(os, "getcwd", lambda: "/")
您还可以向它传递一个函数,而不是使用lambda

import os.path
def getssh(): # pseudo application code
    return os.path.join(os.path.expanduser("~admin"), '.ssh')

def test_mytest(monkeypatch):
    def mockreturn(path):
        return '/abc'
    monkeypatch.setattr(os.path, 'expanduser', mockreturn)
    x = getssh()
    assert x == '/abc/.ssh'

# You can still use lambda when passing arguments, e.g.
# monkeypatch.setattr(os.path, 'expanduser', lambda x: '/abc')
如果您的应用程序与文件系统有很多交互,那么使用类似的东西可能会更容易,因为模仿会变得乏味和重复。

模仿还是模仿? 就我个人而言,我发现在文件系统中有很多边缘情况(如使用正确的权限打开文件、字符串与二进制文件、读/写模式等),使用一个精确的伪文件系统可以发现许多通过模拟可能无法发现的bug。在本例中,我将检查的模块(它具有相同接口的各种具体实现,因此您可以在代码中交换它们)

嘲笑(而且没有猴子修补!): 也就是说,如果您真的想模拟,可以使用Python的库轻松实现:


上面的示例仅演示了通过模拟
open()
方法来创建和写入文件,但您也可以轻松地模拟任何方法。

文件系统的概念太宽泛了。它可能是任何东西。你到底想要什么?@Leonardo.Z:任何与文件系统的交互。我最关心的是创建、打开和删除文件和目录。在其他语言中,可以模拟整个文件系统。该模块是否有帮助?
import os.path
def getssh(): # pseudo application code
    return os.path.join(os.path.expanduser("~admin"), '.ssh')

def test_mytest(monkeypatch):
    def mockreturn(path):
        return '/abc'
    monkeypatch.setattr(os.path, 'expanduser', mockreturn)
    x = getssh()
    assert x == '/abc/.ssh'

# You can still use lambda when passing arguments, e.g.
# monkeypatch.setattr(os.path, 'expanduser', lambda x: '/abc')
# production code file; note the default parameter
def make_hello_world(path, open_func=open):
    with open_func(path, 'w+') as f:
        f.write('hello, world!')

# test code file
def test_make_hello_world():
    file_mock = unittest.mock.Mock(write=unittest.mock.Mock())
    open_mock = unittest.mock.Mock(return_value=file_mock)

    # When `make_hello_world()` is called
    make_hello_world('/hello/world.txt', open_func=open_mock)

    # Then expect the file was opened and written-to properly
    open_mock.assert_called_once_with('/hello/world.txt', 'w+')
    file_mock.write.assert_called_once_with('hello, world!')