Mocking Files en Java – Mock Contents – Mockito

Soy bastante nuevo en la burla, y he estado tratando de burlarme de los contenidos reales (básicamente, creo un archivo virtual solo en la memoria) para que no se escriban datos en el disco en ningún momento.

He intentado soluciones como burlar el archivo y burlar tantas propiedades que puedo deducir tanto como sea posible, y luego escribir en él con un escritor de archivos / bufferedwriter, pero esas no funcionan bien, ya que necesitan una solución canónica. caminos. ¿Alguien encontró una solución que no sea esta o similar, pero que me estoy acercando a este error?

Lo he estado haciendo así:

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

Cualquier idea u orientación sería muy útil. En algún lugar después de esto, básicamente bash leer el archivo usando otra clase. Yo trataría de burlarme de algún tipo de flujo de entrada, pero la otra clase no toma un flujo de entrada, ya que es la clase de manejo del proyecto.

Parece que buscas objectives contradictorios. Por un lado, intenta evitar escribir datos en el disco, lo que no es un mal objective en las pruebas. Por otro lado, intentas probar tu clase de manejo de E / S, lo que significa que trabajarás con utilidades del sistema que suponen que tu File funcionará con llamadas nativas. Como tal, aquí está mi guía:

  • No intentes burlarte de un File . Simplemente no lo hagas Demasiadas cosas nativas dependen de ello.
  • Si puede, divida el código de manejo de E / S en el medio que abre un File y lo convierte en un Reader , y la mitad que analiza HTML fuera del Reader .
  • En ese momento, no necesita ningún simulacro, solo construya un StringReader para simular la fuente de datos.
  • Si bien maneja muy bien las pruebas de su unidad, es posible que también desee escribir una prueba de integración que utilice un archivo temporal y asegurarse de que se lea correctamente. (¡Gracias a Brice por agregar ese consejo!)

No tenga miedo de refactorizar su clase para facilitar las pruebas, como aquí:

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

En este punto, la lógica en el method es tan sencilla que no vale la pena probarla, y la lógica en methodForTest es tan fácil de acceder que puede probarla en gran medida.

Una forma de burlarse de las llamadas de E / S (con Java 7 sería la clase final de NIO java.nio.file.Files ) es envolver las llamadas necesarias en su propia clase y simularlas:

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

La lógica de negocio se encuentra en ImageManager :

 FileHelper fileHelperMock = Mockito.mock(new FileHelper()); ImageManager imageManager = new ImageManagerImpl(fileHelperMock); 

La prueba verificará la llamada al método createDirectory() en tu simulacro:

 imageManager.save("directory"); Mockito.verify(fileHelperMock).createDirectory("directory"); 

Utilizaría este método durante el desarrollo impulsado por prueba en el que no quiero contaminar las pruebas con la gestión real de archivos (por ejemplo, eliminar directorios / archivos creados en un bloque finally en cada prueba unitaria).

Luego, tendré pruebas de aceptación que cubrirán todos los casos de uso con el manejo real de archivos.