我将在一个大量使用IO操作(在这种情况下为文件系统)的项目中引入测试。系统会不断打开/关闭文件,检查文件是否存在,将其删除等等。
很快变得显而易见的是,常规的模拟并没有太大用处,因为这会使我的测试难以设置和推理。另一方面,拥有一个伪造的文件系统会很棒,而且我认为很容易设置。
似乎红宝石家伙又做了一次,正是我在红宝石中要求的:http : //ozmm.org/posts/fakefs.html。
Java有什么远程相似之处吗?
我将在一个大量使用IO操作(在这种情况下为文件系统)的项目中引入测试。系统会不断打开/关闭文件,检查文件是否存在,将其删除等等。
很快变得显而易见的是,常规的模拟并没有太大用处,因为这会使我的测试难以设置和推理。另一方面,拥有一个伪造的文件系统会很棒,而且我认为很容易设置。
似乎红宝石家伙又做了一次,正是我在红宝石中要求的:http : //ozmm.org/posts/fakefs.html。
Java有什么远程相似之处吗?
Answers:
Google具有Java 7的FileSystemProvider的开源内存中实现。该项目称为jimfs。
如果您使用Java 6或更早版本,则有另一种选择:以前我曾使用Apache Commons VFS取得了巨大成功。看起来很像另一个提到的自定义FileSystemProvider,它是Java 7中的一个答案。
Path
是无意中使用的)
在Java 6和更早的版本中,这很困难,因为类喜欢Java类,File
并且FileInputStream
没有提供分发到Java空间中不同的“虚拟文件系统”的方法。
在Java 7中,支持虚拟文件系统。请参阅开发自定义文件系统提供程序。我不知道这是否能让您做自己想做的事,但这是一个开始寻找的好地方。
嗯 由于实际上似乎没有任何伪造的文件系统,我想我将自己实现一个最小的实现。使用FileSystemProvider我一无所获
实际上,您确实可以通过使用FileSystemProvider来获胜:
您实施的某些东西(如果根据开放源代码许可发布)可能对您所在位置的其他人或其他目的非常有用。
如果决定切换到其他人可能现在正在使用的FileSystemProvider,则可以使自己更轻松。
您可以org.junit.rules.TemporaryFolder
从JUnit包中使用:
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");
您可以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("xyz").getAbsolutePath()
绝对没有任何除返回该文件的路径将有,如果它的存在。它不会更改文件系统;它不会更改文件系统。如果文件不存在,它仍然返回路径的字符串,并且不创建文件。您“看到发生了什么”是什么意思?
File
是不是最终在我的OpenJDK 7
MockFTPServer似乎有几个伪文件系统实现(Unix / Windows)
看起来您可以将这些伪造的文件系统实现与任何FTP概念完全分开使用。我现在出于与您概述的目的完全相同的目的进行尝试。
我不确定具体的框架,但是就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了,但是希望您能有所作为。希望我不会在这里低估这个问题并且过于简单化!
当然,所有这些都假设您是在进行真正的单元测试,即测试最小可能的代码单元,而不是整个系统。对于集成测试,需要一种不同的方法。
Arquillian项目的ShrinkWrap似乎在内存FileSystem中包含了符合NIO的标准
您可以通过执行以下操作来创建一个简单的内存文件系统:
FileSystem fs = ShrinkWrapFileSystems.newFileSystem(ShrinkWrap.create(GenericArchive.class))
我在搜索“ Fake java FileSystem”时发现了这个问题。不幸的是,这就是我发现的全部。所以我自己写了这个假的FileSystem:https : //github.com/dernasherbrezon/mockfs
我正在使用它在读取/写入文件期间模拟IOException。IOException可能由于“没有磁盘空间”而发生,这几乎不可能通过其他方式进行模拟。
它有点旧,此解决方案似乎仅是Linux,但看起来不错 https://www.google.co.il/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=tmpfs%20on% 20ubuntu
tmpfs是内存中映射的目录(重新启动后数据会消失)。装入后,可以将数据复制到其中并从内存中进行处理。