【问题标题】:Are there any Fake File System frameworks for Java? [closed]是否有任何适用于 Java 的假文件系统框架? [关闭]
【发布时间】:2011-08-07 01:47:07
【问题描述】:

我在一个大量使用 IO 操作(在本例中为文件系统)的项目中引入测试。系统不断打开/关闭文件,检查文件是否存在,删除它们等等。

很快就很明显,定期模拟不会有太大用处,因为这会使我的测试难以设置和推理。另一方面,拥有一个假文件系统会很棒,而且我认为它很容易设置。

似乎 ruby​​ 人又做了一次,这正是我在 ruby​​ 中所要求的:http://ozmm.org/posts/fakefs.html

Java 有什么类似的东西吗?

【问题讨论】:

  • 它看起来像是在没有静态类型系统的语言中更容易实现的应用程序级别。在 Java 中,File/FileInputStream/FileOutputStream 总是引用底层系统的文件系统——如果你不修补 VM。
  • JavaFileManagerFileSystemView 之类的接口可以实现,但大多数程序不会使用它们。
  • @1st 评论:我很清楚这一点。我目前已将 File 的所有用途替换为我自己的 Filename,该文件名仅包含文件名作为字符串。所有的 IO 逻辑都集中在一个 IFileSystem 接口上。我遇到的问题是,按照我需要的方式实现假文件系统仍然需要一整天的工作(支持文件+文件夹+隐藏文件+重命名+仅从文件名中获取路径+ ...) 并对其进行测试,以知道它实际上是正确的。
  • 既然你在 OP 中提到了 Ruby,我想在这里补充一点,C# 中也有一个等价物,System.IO.Abstractions,我最近开始使用它并且非常好。

标签: java unit-testing testing mocking


【解决方案1】:

Google 有一个 Java 7 FileSystemProvider 的开源内存实现。 project is called jimfs


如果您使用 Java 6 或更早版本,还有一个替代方案:我之前使用过 Apache Commons VFS 并取得了巨大成功。它似乎很像另一个回答者提到的 Java 7 中的自定义 FileSystemProvider。

pre-loaded 带有几个文件系统实现:文件、RAM、S/FTP 和 Jar 等等。我也见过plugin for S3

【讨论】:

  • +1 到 jimfs,这使我无需进行任何更改即可测试我的代码。 (我偶然使用了Path
  • 请注意,如果您使用的库尝试采用路径并执行 toFile,则不支持此操作。
【解决方案2】:

在 Java 6 和更早的版本中,这很困难,因为像 FileFileInputStream 这样的类无法分派到 Java 空间中的不同“虚拟文件系统”。

在 Java 7 中,支持虚拟文件系统;见Developing a Custom File System Provider。我不知道这是否能让你做你想做的事,但这是一个开始寻找的好地方。


嗯。由于实际上似乎没有任何假文件系统,我想我将自己实现一个最小的实现。使用 FileSystemProvider 我一无所获

实际上,使用 FileSystemProvider 确实会赢:

  • 您实现的某些东西(如果根据开源许可发布)可能对您所在职位的其他人以及其他目的非常有用。

  • 如果您决定切换到其他人可能正在使用的 FileSystemProvider,您会更轻松。

【讨论】:

  • 很有趣,但似乎我仍然必须自己实现文件系统,没那么有用;-(
  • 至少它允许你这样做。正如您自己所说 - “设置起来很容易”
  • 嗯。由于实际上似乎没有任何假文件系统,我想我将自己实现一个最小的实现。使用 FileSystemProvider 我什么也没赢。
  • @devoured elysium - 查看我的更新。
  • +1 推荐写作和开源解决方案
【解决方案3】:

您可以使用JUnit 包中的org.junit.rules.TemporaryFolder

TemporaryFolder Rule 允许创建保证在测试方法完成时删除的文件和文件夹(无论是通过还是失败):

示例:

final TemporaryFolder testFolder = new TemporaryFolder();
testFolder.create();
final Path filePath = testFolder.newFile("input.txt").toPath();
final Path dirPath = testFolder.newFolder("subfolder").toPath();

或者退出 .toPath() 部分:

final File filePath = testFolder.newFile("input.txt");

【讨论】:

  • 临时文件夹不在内存中。
【解决方案4】:

您可以通过将 API 更改为使用 OutputStream 而不是 File 来抽象使用 File,通过使用“在某处写入数据”的意图,然后在您的生产代码,但从你的测试中传递一个ByteArrayOutputStreamByteArrayOutputStream 是一个内存流,所以它非常快,您可以使用它的方法简单地检查它的内容——它非常适合测试。如果你想读取数据,还有对应的ByteArrayInputStream

文件系统通常非常快 - 除非您在测试中执行大量文件 I/O,否则我不会打扰。

请注意,创建 java File 对象不会在磁盘上创建文件,即以下代码不会对磁盘​​造成任何更改:

File f = new File("somepath"); // doesn't create a file on disk

【讨论】:

  • new File("something") 不会在磁盘上创建文件,但如果您尝试运行它的几乎任何方法,它将使用文件系统。试试 new File("xyz").getAbsolutePath() 看看我的意思..
  • 我认为人们认为我主要关心的是速度。不是。
  • 我发现抽象出像文件系统这样的任何资源总是一个好习惯(就像你将数据访问层写入数据库一样)。这通常是通过在最低级别的类周围编写一个接口和一个瘦包装器来实现的。如果您在程序的最高级别使用依赖注入,您可以非常轻松地通过您的应用程序传播模拟文件系统(注意它不必使用模拟框架,只是接口的“虚拟”实现)。
  • @devouredelysium new File("xyz").getAbsolutePath() 除了返回文件具有如果存在的路径之外,什么都不做。它不会改变文件系统;如果文件不存在,它仍然返回路径的字符串并且不创建文件。 “看看会发生什么”是什么意思?
  • File 在我的 OpenJDK 7 中不是最终版本。
【解决方案5】:

Jimfs,由 Google 提供,是一个内存 NIO 文件系统,非常适合测试。

【讨论】:

    【解决方案6】:

    一种简单的方法是使用系统提供完全基于 RAM 的文件系统的方式 - Linux 上为 tempfs,Windows 上为 RAM disk

    【讨论】:

    • 我不认为这比使用真正的文件系统(速度除外)更好。
    • 是的,速度(和磁盘磨损)将是主要原因。抱歉,我可能误解了你的目标。
    • 我的目标是简化我的测试。我目前不关心性能。
    【解决方案7】:

    MockFTPServer 似乎有几个假文件系统实现(Unix/Windows)

    看起来您可以完全独立于任何 FTP 概念来使用这些假文件系统实现。我现在正在尝试这样做,目的与您概述的完全相同。

    【讨论】:

    • 我正在使用 UnixFakeFileSystem。作为我的 FileSystem 抽象的假实现工作得很好。
    【解决方案8】:

    我不确定具体的框架,但就 OOP 而言,一种通用的方法是在任何文件访问代码(大量接口!)之上编写一些抽象层,也许还有一个外观以简化常见操作的使用。然后你只需在你当前正在测试的代码下面模拟一层,然后它本质上就是一个假文件系统(或者至少你正在测试的代码不会知道其他情况)。

    如果您考虑使用依赖注入框架来为您处理此问题,它将简化切换组件以实现接口的伪造实现的能力。如果您遵循控制反转的模式,将任何依赖项传递到您正在测试的类的构造函数中,这也将便于测试。

    public interface IFileSystem {
       IFileHandle Load(string path);
       //etc
    }
    
    public class ClassBeingTested {
       public ClassBeingTested(IFileSystem fileSystem) {
          //assign to private field
       }
    
       public void DoSomethingWithFileSystem() {
           //utilise interface to file system here
           //which you could easily mock for testing purposes
           //by passing a fake implementation to the constructor
       }
    }
    

    我希望我的 java 是正确的,我很久没有写 java 了,但希望你能明白。希望我没有低估这里的问题并且过于简单化!

    当然,这一切都假设您的意思是真正的单元测试,即测试尽可能小的代码单元,而不是整个系统。对于集成测试,需要一种不同的方法。

    【讨论】:

    • 一个假文件系统需要有自己的逻辑——它和其他文件系统一样,但只存在于内存中。我想避免自己编写这样的文件系统。
    • 您希望模仿什么类型的文件系统操作?锁定文件?读/写?还是打开文件、检查目录存在、创建文件等简单的东西?
    • 主要是简单的操作,检查文件是文件还是目录,如果它们存在,创建文件,删除文件。当然,这同时支持多个文件夹和“从这个文件名获取路径”、“从绝对路径获取相对路径”等操作。
    • 我认为正如我所说,围绕物理文件系统创建一个抽象,并始终在整个应用程序中使用它(始终针对界面进行编码)。然后只需使用依赖注入通过您的测试主题进行传播。我知道这是单调的工作,但作为程序员,我们必须做这些事情才能清晰地分离关注点并便于测试:)
    • 你真的没有得到这里的要求。如果我正在寻找一个假文件系统,那一定是因为我已经在我的应用程序中对整个文件系统进行了抽象(如 OP 的评论中所述)。我只是需要一个文件系统的假实现来在我的测试中使用..
    【解决方案9】:

    ShrinkWrap from the Arquillian project 看起来在内存文件系统中包含一个兼容 NIO 的文件系统

    您可以通过执行以下操作来创建一个简单的内存文件系统:

    FileSystem fs = ShrinkWrapFileSystems.newFileSystem(ShrinkWrap.create(GenericArchive.class))
    

    【讨论】:

    • 是否支持file://协议,找不到文档....
    【解决方案10】:

    另外两个用于java的内存文件系统是,

    memoryfilesystem

    ephemeralfs

    两者都实现了 NIO.2 文件系统 api。

    【讨论】:

      【解决方案11】:

      我在谷歌上搜索“Fake java FileSystem”并找到了这个问题。不幸的是,这就是我发现的全部。所以我自己写了这个假文件系统:https://github.com/dernasherbrezon/mockfs

      我在读/写文件期间使用它来模拟 IOExceptions。例如,IOException 可能由于“没有磁盘空间”而发生,这几乎不可能通过其他方式模拟。

      【讨论】:

        【解决方案12】:

        它有点旧,这个解决方案似乎只是 linux 但看起来不错 https://www.google.co.il/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=tmpfs%20on%20ubuntu

        tmpfs 是内存中的映射目录(数据在重启时消失)。挂载后,可以将数据复制到其中并从内存中处理。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-09-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-31
          相关资源
          最近更新 更多