Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.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
Java中的模拟文件-Mock Contents-Mockito_Java_File_Mockito - Fatal编程技术网

Java中的模拟文件-Mock Contents-Mockito

Java中的模拟文件-Mock Contents-Mockito,java,file,mockito,Java,File,Mockito,我对模拟非常陌生,我一直在尝试模拟实际内容(基本上只在内存中创建一个虚拟文件),以便在任何时候都不会将数据写入磁盘 我尝试过一些解决方案,比如模拟文件,模拟尽可能多的属性,然后用filewriter/bufferedwriter将其写入,但这些方法效果不好,因为它们需要规范路径。有人找到了除此之外的解决方案或类似的解决方案,但我的做法是错误的吗 我一直是这样做的: private void mocking(){ File badHTML = mock(File.class); /

我对模拟非常陌生,我一直在尝试模拟实际内容(基本上只在内存中创建一个虚拟文件),以便在任何时候都不会将数据写入磁盘

我尝试过一些解决方案,比如模拟文件,模拟尽可能多的属性,然后用filewriter/bufferedwriter将其写入,但这些方法效果不好,因为它们需要规范路径。有人找到了除此之外的解决方案或类似的解决方案,但我的做法是错误的吗

我一直是这样做的:

private void mocking(){
    File badHTML = mock(File.class);
    //setting the properties of badHTML
    when(badHTML.canExecute()).thenReturn(Boolean.FALSE);
    when(badHTML.canRead()).thenReturn(Boolean.TRUE);
    when(badHTML.canWrite()).thenReturn(Boolean.TRUE);
    when(badHTML.compareTo(badHTML)).thenReturn(Integer.SIZE);
    when(badHTML.delete()).thenReturn(Boolean.FALSE);
    when(badHTML.getFreeSpace()).thenReturn(0l);
    when(badHTML.getName()).thenReturn("bad.html");
    when(badHTML.getParent()).thenReturn(null);
    when(badHTML.getPath()).thenReturn("bad.html");
    when(badHTML.getParentFile()).thenReturn(null);
    when(badHTML.getTotalSpace()).thenReturn(0l);
    when(badHTML.isAbsolute()).thenReturn(Boolean.FALSE);
    when(badHTML.isDirectory()).thenReturn(Boolean.FALSE);
    when(badHTML.isFile()).thenReturn(Boolean.TRUE);
    when(badHTML.isHidden()).thenReturn(Boolean.FALSE);
    when(badHTML.lastModified()).thenReturn(System.currentTimeMillis());
    when(badHTML.mkdir()).thenReturn(Boolean.FALSE);
    when(badHTML.mkdirs()).thenReturn(Boolean.FALSE);
    when(badHTML.setReadOnly()).thenReturn(Boolean.FALSE);
    when(badHTML.setExecutable(true)).thenReturn(Boolean.FALSE);
    when(badHTML.setExecutable(false)).thenReturn(Boolean.TRUE);
    when(badHTML.setReadOnly()).thenReturn(Boolean.FALSE);

    try {
        BufferedWriter bw = new BufferedWriter(new FileWriter(badHTML));
        /*
          badHTMLText is a string with the contents i want to put into the file, 
          can be just about whatever you want
         */
        bw.append(badHTMLText);
        bw.close();

    } catch (IOException ex) {
        System.err.println(ex);
    }
}
任何想法或指导都会非常有用。
在这之后的某个地方,我基本上尝试使用另一个类读取文件。我会尝试模拟某种输入流,但另一个类不接受inputstream,因为它是项目的io处理类。

您似乎在追求相互矛盾的目标。一方面,您试图避免将数据写入磁盘,这在测试中是一个不错的目标。另一方面,您正在尝试测试I/O处理类,这意味着您将使用假定您的
文件
将处理本机调用的系统实用程序。因此,以下是我的指导:

  • 不要试图模仿
    文件
    。别这样。太多的本土事物依赖于它
  • 如果可以,将I/O处理代码拆分为打开
    文件的一半,并将其转换为
    读取器
    ,以及从
    读取器中解析HTML的一半
  • 在这一点上,您根本不需要模拟——只需要构造一个模拟数据源的模型
  • 虽然这样可以很好地处理单元测试,但您可能还希望编写一个使用的集成测试,并确保它的读取正确。(感谢Brice添加此提示!)
不要害怕重构类以简化测试,如下所示:

class YourClass {
  public int method(File file) {
    // do everything here, which is why it requires a mock
  }   
}   

class YourRefactoredClass {
  public int method(File file) {
    return methodForTest(file.getName(), file.isFile(),
        file.isAbsolute(), new FileReader(file));
  }   

  /** For testing only. */
  int methodForTest(
      String name, boolean isFile, boolean isAbsolute, Reader fileContents) {
    // actually do the calculation here
  }   
}   

class YourTest {
  @Test public int methodShouldParseBadHtml() {
    YourRefactoredClass yrc = new YourRefactoredClass();
    assertEquals(42, yrc.methodForTest(
        "bad.html", true, false, new StringReader(badHTMLText));
  }   
}   
此时,
方法
中的逻辑非常简单,不值得测试,
methodForTest
中的逻辑非常容易访问,因此您可以对其进行大量测试。

模拟I/O调用的一种方法(对于Java 7,将是NIO最终类
Java.NIO.file.Files
)是将所需的调用封装在您自己的类中并模拟它:

public class FileHelper {

    public Path createDirectory(String directoryName) throws IOException {
        return Files.createDirectory(Paths.get(directoryName));
    }

    public boolean exists(String name) throws IOException {
        return Files.exists(Paths.get(name), LinkOption.NOFOLLOW_LINKS);
    }

}
业务逻辑位于
图像管理器中

FileHelper fileHelperMock = Mockito.mock(new FileHelper());
ImageManager imageManager = new ImageManagerImpl(fileHelperMock);
该测试将验证对模拟上的
createDirectory()
方法的调用:

imageManager.save("directory");
Mockito.verify(fileHelperMock).createDirectory("directory");
在测试驱动的开发过程中,我会使用这种方法,我不想用真正的文件管理(例如,在每个单元测试的finally块中删除创建的目录/文件)来污染测试


然后,我将进行验收测试,测试将覆盖每个具有真实文件处理的用例。

测试的目标是什么?为什么不模拟BufferedWriter呢?BufferedWriter将文件写入该文件中,以便其他类可以处理模拟的文件。另一个测试用于测试html文件的内容并对其进行分级。请尝试spy(新文件(…)而不是模拟文件)。然后,您可以在when()中只更改您真正想要更改的行为,而不必处理整个API。不要模拟或监视文件!这不是正确的方法。这是一个测试反模式。一般来说,不要模仿你不拥有的类型!。相反,重点是在访问文件的代码和处理内容的代码之间拆分功能。杰夫的答案是正确的!我想说的是,您完全可以(而且在某些情况下应该)模拟您不拥有的代码,但只有接口!您的代码无论如何都应该针对接口,而不是具体的实现,如果可能的话。但是java.io.File不满足接口要求。所以不适合模拟。+1用于不模拟文件并将逻辑拆分为具有不同关注点的不同对象。同样,从更一般的角度来说,模仿你不拥有的类型根本不是一个好主意。所以我要重新表述Jeff所说的,但要编写一个集成测试,该测试将断言将打开和/或写入文件的代码,并提供您自己的类型或
读取器
/
编写器
,并为将处理内容的代码编写一个单元测试,当然,您不必嘲笑
阅读器
/
编写器
,而是在现有实现上使用或断言内容,如
StringReader
/
StringWriter
。是的,如果我可以一直编辑它,我会这么做。从技术上讲,我可以编辑它,但不能,因为它会破坏其他人当前的可用性。Matt--就像上面的
方法
一样,您通常可以插入自己的测试访问,而无需实际更改外部API。我知道这可能不是项目中你的一部分,但如果你的工作是测试其他人难以测试的类,那么通常值得尝试移动一些东西,使其更干净、更容易。祝你好运!:)谢谢我决定完全忽略它,甚至不尝试模拟这些,只需要使用真实的文件,因为尝试模拟任何东西或替换任何妨碍其余工作的东西。使用虚拟文件系统(如JIMFS)怎么样?当我测试将文件表单a复制到B的服务,并让它复制到虚拟文件系统中时,这仍然是一个单元测试吗?这是个好主意吗?