是否有用于Java的伪造文件系统框架?[关闭]


83

我将在一个大量使用IO操作(在这种情况下为文件系统)的项目中引入测试。系统会不断打开/关闭文件,检查文件是否存在,将其删除等等。

很快变得显而易见的是,常规的模拟并没有太大用处,因为这会使我的测试难以设置和推理。另一方面,拥有一个伪造的文件系统会很棒,而且我认为很容易设置。

似乎红宝石家伙又做了一次,正是我在红宝石中要求的:http : //ozmm.org/posts/fakefs.html

Java有什么远程相似之处吗?


1
在没有静态类型系统的情况下,使用语言看起来更容易实现应用程序级别。在Java中,如果不修补VM,则File / FileInputStream / FileOutputStream始终将引用基础系统的文件系统。
圣保罗Ebermann

您可以实现类似JavaFileManagerFileSystemView的接口,但是大多数程序不会使用它们。
圣保罗Ebermann

@第一评论:我很清楚这一点。我目前已将File的所有用法替换为我自己的文件名,该文件名仅包含文件名作为字符串。所有的IO逻辑都集中在IFileSystem接口上。我遇到的问题是,按照我需要的方式来实施伪造的文件系统仍然需要整整一天的工作(支持文件+文件夹+隐藏文件+重命名+仅从文件名获取路径+ ...)并对其进行测试,以了解它实际上是正确的。
2011年

1
自从您在OP中提到Ruby以来,我想在这里补充一下,C#也有一个等效项,即System.IO.Abstractions,我最近开始使用它并且非常好。
julealgon

Answers:


52

Google具有Java 7的FileSystemProvider的开源内存中实现。该项目称为jimfs


如果您使用Java 6或更早版本,则有另一种选择:以前我曾使用Apache Commons VFS取得了巨大成功。看起来很像另一个提到的自定义FileSystemProvider,它是Java 7中的一个答案。

预装有几种文件系统实现:文件,RAM,S / FTP和Jar(仅举几例)。我也看到了S3插件


6
+1到jimfs,这使我无需进行任何更改即可测试代码。(我Path是无意中使用的)
user1071136 2014年

35

在Java 6和更早的版本中,这很困难,因为类喜欢Java类,File并且FileInputStream没有提供分发到Java空间中不同的“虚拟文件系统”的方法。

在Java 7中,支持虚拟文件系统。请参阅开发自定义文件系统提供程序。我不知道这是否能让您做自己想做的事,但这是一个开始寻找的好地方。


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

实际上,您确实可以通过使用FileSystemProvider来获胜:

  • 您实施的某些东西(如果根据开放源代码许可发布)可能对您所在位置的其他人或其他目的非常有用。

  • 如果决定切换到其他人可能现在正在使用的FileSystemProvider,则可以使自己更轻松。


有趣,但是似乎我仍然必须自己实现文件系统,而不是那么有用;-(
吞噬了极乐世界

6
至少它允许您这样做。正如您自己所说的那样- “设置起来很容易”
斯蒂芬·C

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

@吞噬的极乐世界-请参阅我的更新。
斯蒂芬·C

2
+1推荐编写和开源解决方案
WickyNilliams 2012年

19

您可以org.junit.rules.TemporaryFolderJUnit包中使用:

TemporaryFolder规则允许创建在测试方法完成时(无论通过还是失败)都将被删除的文件和文件夹:

例:

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");

TemporaryFolder不在内存中。
progonkpa

8

您可以File通过将API改为使用OutputStream而不是来使用“在某处写入数据”的意图来抽象化的使用File,然后FileOutputStream在生产代码中传递API a ,但从ByteArrayOutputStream测试中传递a 。AByteArrayOutputStream是内存中的流,因此它非常快,您可以使用其方法简单地检查其内容-非常适合测试。ByteArrayInputStream如果要读取数据,也有相应的内容

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

请注意,创建JavaFile对象并不会在磁盘上创建一个文件,即下面的代码不会导致任何改变磁盘:

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

new File(“ something”)不会在磁盘上创建文件,但是如果您尝试运行它的几乎任何方法,它将使用文件系统。尝试新的文件(“XYZ”)getAbsolutePath(),看看我的意思..。
吞噬极乐世界

1
我认为人们认为我主要关心的是速度。它不是。
2011年

1
我发现将所有资源(例如文件系统)抽象出来是一种很好的做法(以同样的方式将数据访问层写入数据库)。这通常是通过在最低级别的类周围编写一个接口和一个薄包装器来实现的。如果您在程序的最高级别使用依赖注入,则可以通过应用程序轻松传播模拟文件系统(注意,它不必使用模拟框架,而只是接口的“虚拟”实现)。
WickyNilliams 2011年

@devouredelysiumnew File("xyz").getAbsolutePath()绝对没有任何除返回该文件的路径,如果它的存在。它不会更改文件系统;它不会更改文件系统。如果文件不存在,它仍然返回路径的字符串,并且不创建文件。您“看到发生了什么”是什么意思?
波希米亚

1
File是不是最终在我的OpenJDK 7
Dzmitry Lazerka

6

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


4

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


我看不出有什么比使用真正的文件系统(除了速度)更好的了。
2011年

是的,速度(和磁盘磨损)将是主要原因。抱歉,也许我确实误会了您的目标。
圣保罗Ebermann

1
我的目标是简化测试。我目前不关心性能。
2011年

4

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

看起来您可以将这些伪造的文件系统实现与任何FTP概念完全分开使用。我现在出于与您概述的目的完全相同的目的进行尝试。


我正在使用UnixFakeFileSystem。作为我的FileSystem抽象的伪实现很好地工作。
Deano'9

2

我不确定具体的框架,但是就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了,但是希望您能有所作为。希望我不会在这里低估这个问题并且过于简单化!

当然,所有这些都假设您是在进行真正的单元测试,即测试最小可能的代码单元,而不是整个系统。对于集成测试,需要一种不同的方法。


1
伪造的文件系统需要具有自己的逻辑-它是与其他文件系统一样的文件系统,但仅存在于内存中。我希望避免自己对这样的文件系统进行编程。
2011年

您要模仿哪种类型的文件系统操作?锁定文件?阅读/写作?还是打开文件,检查目录是否存在,创建文件之类的简单内容?
WickyNilliams 2011年

通常是一些简单的操作,用于检查文件是文件还是目录(如果存在),创建文件或删除文件。这,当然,同时支持多种文件夹和操作,比如“得到这个文件名的路径”,“距离的绝对路径获得的相对路径”,等等
吞噬极乐世界

我认为正如我所说,围绕物理文件系统创建摘要,并在整个应用程序中始终使用该摘要(始终对接口进行编码)。然后只需使用依赖项注入来传播您的测试对象即可。我知道这是单调的工作,但是作为程序员,我们必须做这些事情才能
清楚

您真的不明白这里的要求。如果我要寻找伪造的文件系统,那一定是因为我已经在我的应用程序中对整个文件系统进行了抽象(如OP的评论中所述)。我只是需要一个假的实现文件系统在我的测试中使用的..
吞噬极乐

2

Arquillian项目的ShrinkWrap似乎在内存FileSystem中包含了符合NIO的标准

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

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

它支持file://协议,找不到文档
吗?



By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.