【问题标题】:How to simulate file IO in Java?如何在 Java 中模拟文件 IO?
【发布时间】:2011-07-27 06:35:42
【问题描述】:

如何创建一个类 MockFile 模仿 java.io.File w.r.t.文件读写?我到处使用我自己的方法而不是new FileInputStream(....)new FileOutputStream(....),所以这部分没有问题(我总是委托给适当的流)。非琐碎部分是我的MockFileInputStreamMockFileOutputStream 在更复杂的情况下的实现。

没有问题,当我先写入文件然后读取它时,我可以简单地使用ByteArrayOutputStream等等。这很简单,但是对于交错读取和写入,它无法工作。有什么比写我自己的ByteArrayOutputStream 更好的主意吗?

【问题讨论】:

  • 为什么要通过文件在同一系统中的组件之间交换数据?为什么不使用临时文件来创建模拟文件?
  • 您可能会在 [这里][1] [1] 找到答案:stackoverflow.com/questions/3148089/…
  • @Peter Lawrey 我不是在尝试交换数据,而是在尝试模仿程序的工作方式(用于某种集成测试)。使用临时文件非常容易,但速度不是很快,尤其是当我只需要几个字节时。
  • 通过临时文件传递几个字节大约需要 10 毫秒。如果这是性能问题,为什么要使用文件?顺便说一句,如果您可以在 unix 上使用 tmpfs,例如/tmp/deleteme.dat,它只需要一小部分时间,因为它实际上并不写入磁盘,只写入内存。
  • @Peter Lawrey “如果这是性能问题,你为什么要使用文件?”在实际运行中,时不时地写入或读取这样的数据是没有问题的,但在测试中情况会更糟。但我同意这可能不值得麻烦,所以我会简单地使用临时文件,至少现在是这样。

标签: java file io


【解决方案1】:

我会使用一个 real 文件和一个真正的 FileInputStreamFileOutputStream。否则你只是在执行测试代码:真的毫无意义。

【讨论】:

  • @EJP 这就像“只是交付给客户,看着他生气。否则你只是在练习测试代码,真的很没有意义。”,不是吗?
  • @maaartinus 你必须解释一下,因为我不明白。测试的目的是测试真实代码而不是测试代码。测试测试代码是一个无限的倒退,它实际上并没有达到目标,这确实是向客户交付工作代码。
  • @EJP 大多数运行的测试实际上由真实代码和测试代码(模拟)的混合组成,对吧?这样我们希望能够捕捉到真实代码中的错误,对吧?模拟有助于隔离问题和/或更快地运行测试(没有缓慢的操作)或降低成本(没有真正的银行业务)或重复(没有真正的核导弹发射),对吗?那么模拟文件系统有什么问题呢?
  • 模拟文件系统没有错。 EJP 的意思(我认为)是不断使用模拟来处理简单的事情最终会产生如此多的模拟,以至于您不再测试真正的代码。它本质上是一个滑坡。也许使用内存文件系统(正如@peter-lawrey 建议的那样)是完美的权衡。您测试与文件系统的真实交互,而不是假设您正确使用了 API。有关详细信息,请参阅java.dzone.com/news/in-memory-virtual-filesystems
  • @maaartinus 它的问题在于它毫无意义。它没有您提到的任何风险,例如启动世界末日或将国债增加三倍,并且OP特别提到他想测试交错,当真正的文件系统这样做时,这已经够难了,更不用说只写的东西了目的。
【解决方案2】:

我创建了一个“WordCounter”类来计算文件中的单词。但是,我想对我的代码进行单元测试,并且单元测试不应该触及文件系统。

因此,通过将实际的文件 IO (FileReader) 重构为它自己的方法(让我们面对现实,标准的 Java 文件 IO 类可能工作,因此我们不会通过测试它们获得太多收益),我们可以测试我们的字数统计逻辑孤立无援。

import static org.junit.Assert.assertEquals;

import java.io.*;

import org.junit.Before;
import org.junit.Test;

public class WordCounterTest {

    public static class WordCounter {

        public int getWordCount(final File file) throws FileNotFoundException {
            return getWordCount(new BufferedReader(new FileReader(file)));
        }

        public int getWordCount(final BufferedReader reader) {
            int wordCount = 0;
            try {
                String line;
                while ((line = reader.readLine()) != null) {
                    wordCount += line.trim().split(" ").length;
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (reader != null) {
                        reader.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return wordCount;
        }
    }

    private static String TEST_CONTENT = "Neque porro quisquam est qui dolorem\n"
            + " ipsum quia dolor sit amet, consectetur, adipisci velit...";

    private WordCounter wordCounter;

    @Before
    public void setUp() {
        wordCounter = new WordCounter();
    }

    @Test
    public void ensureExpectedWordCountIsReturned() {
        assertEquals(14, wordCounter.getWordCount(new BufferedReader(new StringReader(TEST_CONTENT))));
    }
}

编辑:我应该注意,如果您的测试与您的代码共享相同的包,您可以降低可见性

public int getWordCount(final BufferedReader reader)

方法让你的公共 API 只公开

public int getWordCount(final File file)

【讨论】:

  • 恐怕你错过了我的问题的第二段......你所做的工作适用于只读或只写,但我需要测试一个组合。这不是单元测试,而是对程序不同部分协作的测试。
猜你喜欢
  • 2020-08-13
  • 1970-01-01
  • 2011-09-23
  • 1970-01-01
  • 1970-01-01
  • 2019-07-02
  • 1970-01-01
  • 1970-01-01
  • 2014-08-20
相关资源
最近更新 更多