¿Existen marcos de sistemas de archivos falsos para Java? [cerrado]

83

Estoy introduciendo pruebas en un proyecto que hace un uso intensivo de operaciones IO (el sistema de archivos, en este caso). El sistema abre / cierra archivos constantemente, comprueba si existen archivos, los elimina, etc.

Pronto se hizo obvio que las burlas regulares no serían de mucha utilidad, ya que eso haría que mis pruebas fueran difíciles de configurar y razonar. Por otro lado, tener un sistema de archivos falso sería increíble y creo que bastante fácil de configurar.

Parece que los chicos de ruby ​​lo hicieron de nuevo, y hay exactamente lo que estoy pidiendo en ruby: http://ozmm.org/posts/fakefs.html .

¿Hay algo remotamente similar para Java?

elisio devorado
fuente
1
Parece que el nivel de aplicación es más fácil de hacer en idiomas sin un sistema de tipos estáticos. En Java, un File / FileInputStream / FileOutputStream siempre se referirá al sistema de archivos del sistema subyacente, si no parchea la VM.
Paŭlo Ebermann
Hay interfaces como JavaFileManager o FileSystemView que puede implementar, pero la mayoría de los programas no las usan.
Paŭlo Ebermann
@ 1er comentario: Soy muy consciente de eso. Actualmente he reemplazado todos los usos de Archivo por un Nombre de archivo propio que solo contiene el nombre del archivo como una cadena. Toda la lógica IO se concentró en una interfaz IFileSystem. El problema que tengo es que aún sería como un día completo de trabajo implementar el sistema de archivos falso de la forma en que lo necesitaba (con soporte para archivos + carpetas + archivos ocultos + cambios de nombre + obtener solo la ruta de un nombre de archivo + ...) y probándolo, para saber que realmente es correcto.
Devoró elisio el
1
Dado que mencionó Ruby en el OP, me gustaría agregar aquí que también hay un equivalente en C #, System.IO.Abstractions que comencé a usar recientemente y es bastante bueno.
julealgon

Respuestas:

52

Google tiene una implementación de código abierto en memoria de FileSystemProvider de Java 7. El proyecto se llama jimfs .


Si usa Java 6 o anterior, hay una alternativa: he usado Apache Commons VFS antes con gran éxito. Parece ser muy parecido al FileSystemProvider personalizado que otro respondedor mencionado está en Java 7.

Viene precargado con varias implementaciones de sistemas de archivos: Archivo, RAM, S / FTP y Jar, por nombrar algunas. También he visto un complemento para S3 .

Michael Deardeuff
fuente
6
+1 a jimfs, lo que me permitió probar mi código sin un solo cambio. (Lo usé Pathpor accidente)
user1071136
35

En Java 6 y versiones anteriores es difícil porque a las clases les gusta Filey FileInputStreamno proporcionan forma de enviar a diferentes "sistemas de archivos virtuales" en el espacio Java.

En Java 7, hay soporte para sistemas de archivos virtuales; consulte Desarrollo de un proveedor de sistema de archivos personalizado . No sé si esto le permitirá hacer lo que quiere hacer, pero es un buen lugar para empezar a buscar.


Meh. Siendo el hecho de que no parece haber ningún sistema de archivos falso, supongo que solo implementaré una implementación mínima por mí mismo. No gano nada usando FileSystemProvider

En realidad, usted gana utilizando FileSystemProvider:

  • Implementas algo que (si se publica bajo una licencia de código abierto) podría ser muy útil para otras personas en tu puesto y para otros fines.

  • Se lo hace más fácil si decide cambiar a un FileSystemProvider en el que otra persona podría estar trabajando en este momento.

Stephen C
fuente
Interesante, pero como parece, todavía tendría que implementar el sistema de archivos por mí mismo, no es tan útil ;-(
devorado elysium
6
Al menos te permite hacer eso. Y como usted mismo dijo, "sería fácil de configurar" .
Stephen C
Meh. Siendo el hecho de que en realidad no parece haber ningún sistema de archivos falso, supongo que solo implementaré una implementación mínima por mí mismo. No gano nada usando FileSystemProvider.
Devoró elisio
@devoured elysium - mira mi actualización.
Stephen C
2
+1 por recomendar la escritura y el código abierto de una solución
WickyNilliams
19

Puede usar org.junit.rules.TemporaryFolderdesde el paquete JUnit :

La regla de carpeta temporal permite la creación de archivos y carpetas que se garantiza que se eliminarán cuando finalice el método de prueba (ya sea que pase o falle):

Ejemplo:

final TemporaryFolder testFolder = new TemporaryFolder();
testFolder.create();
final Path filePath = testFolder.newFile("input.txt").toPath();
final Path dirPath = testFolder.newFolder("subfolder").toPath();

Alternativamente, salga de la .toPath()pieza:

final File filePath = testFolder.newFile("input.txt");
thomas.mc.work
fuente
TemporaryFolder no está en memoria.
progonkpa
8

Puede abstraer el uso de Fileusando la intención de "algún lugar para escribir datos" cambiando su API para usar un en OutputStreamlugar de a File, luego pasar el API a FileOutputStreamen su código de producción, pero pasarlo a ByteArrayOutputStreamde sus pruebas. A ByteArrayOutputStreames un flujo en memoria, por lo que es muy rápido y simplemente puede inspeccionar su contenido utilizando sus métodos; es perfecto para realizar pruebas. También está el correspondiente ByteArrayInputStreamsi desea leer datos.

Los sistemas de archivos son generalmente bastante rápidos; a menos que estuvieras haciendo una gran cantidad de E / S de archivos en tus pruebas, no me molestaría.

Tenga en cuenta que la creación de un Fileobjeto java no crea un archivo en el disco, es decir, el siguiente código no causa ningún cambio en el disco:

File f = new File("somepath"); // doesn't create a file on disk
Bohemio
fuente
new File ("algo") no creará un archivo en el disco, pero si intenta ejecutar casi cualquiera de sus métodos, utilizará el sistema de archivos. Pruebe el nuevo Archivo ("xyz"). GetAbsolutePath () para ver a qué me refiero ..
devorado elysium
1
Creo que la gente está asumiendo que mi principal preocupación es la velocidad. No lo es.
devoró elisio el
1
Creo que siempre es una buena práctica abstraer cualquier recurso como los sistemas de archivos (de la misma manera que escribiría una capa de acceso a datos en la base de datos). esto generalmente se logra escribiendo una interfaz y una envoltura delgada alrededor de la clase de nivel más bajo. si usa la inyección de dependencia en el nivel más alto de su programa, puede propagar muy fácilmente un sistema de archivos simulado (tenga en cuenta que no tiene que usar un marco simulado, solo una implementación "ficticia" de la interfaz) a través de su aplicación.
WickyNilliams
@devouredelysium new File("xyz").getAbsolutePath()no hace absolutamente nada en absoluto Excepto devolver la ruta que el archivo podría tener si existiera. No cambia el sistema de archivos; si el archivo no existe, todavía devuelve la cadena de la ruta y no crea un archivo. ¿Qué quisiste decir con "ver qué pasa"?
Bohemian
1
Fileno es final en mi OpenJDK 7.
Dzmitry Lazerka
6

Jimfs , de Google, es un sistema de archivos NIO en memoria, ideal para pruebas.

pron
fuente
4

Una forma sencilla sería utilizar la forma de su sistema de proporcionar un sistema de archivos basado totalmente en RAM: tempfs en Linux, un disco RAM en Windows.

Paŭlo Ebermann
fuente
No veo cómo eso sería mejor que usar el verdadero sistema de archivos (que no sea la velocidad).
devoró elisio el
Sí, la velocidad (y el desgaste del disco) sería la razón principal. Lo siento, tal vez entendí mal tu objetivo.
Paŭlo Ebermann
1
Mi objetivo es facilitar mis pruebas. Actualmente no me preocupa el rendimiento.
devoró elisio el
4

MockFTPServer parece tener un par de implementaciones de sistemas de archivos falsos (Unix / Windows)

Parece que puede usar estas implementaciones de sistemas de archivos falsos de forma bastante separada de cualquier concepto de FTP. Estoy probando esto ahora exactamente para los mismos objetivos que ha descrito.

Deano
fuente
Estoy usando UnixFakeFileSystem. Funciona muy bien como una implementación falsa para mi abstracción FileSystem.
Deano
2

No estoy seguro acerca de marcos específicos, pero un enfoque general en términos de POO sería escribir algunas capas abstractas encima de cualquier código de acceso a archivos (¡interfaces en abundancia!) y quizás una fachada para facilitar el uso de operaciones comunes. luego simplemente simula una capa debajo del código que está probando actualmente y luego es esencialmente un sistema de archivos falso (o al menos el código que está probando no sabrá lo contrario).

Si busca usar un marco de inyección de dependencia para manejar esto, facilitará la capacidad de cambiar componentes para una implementación falsa de una interfaz. Si sigue los patrones de inversión de control, pasando cualquier dependencia al constructor de la clase que está probando, esto también facilitará la prueba.

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

Espero que mi java sea correcto, no he escrito java en mucho tiempo, pero espero que te enteres. ¡Ojalá no esté subestimando el problema aquí y siendo demasiado simplista!

por supuesto, todo esto es asumiendo que te refieres a verdaderas pruebas unitarias, es decir, probar las unidades de código más pequeñas posibles, y no un sistema completo. para las pruebas de integración se necesita un enfoque diferente.

WickyNilliams
fuente
1
Un sistema de archivos falso debe tener lógica propia: es un sistema de archivos como cualquier otro, pero que solo existe en la memoria. Me gustaría evitar tener que programarme un sistema de archivos de este tipo.
devoró elisio el
¿Qué tipo de operaciones del sistema de archivos desea imitar? bloqueo de archivos? ¿leyendo escribiendo? o cosas sencillas como abrir archivos, comprobar que existen directorios, crear archivos?
WickyNilliams
En su mayoría, operaciones simples que se ocupan de verificar si los archivos son archivos o directorios, si existen, para crear archivos, para eliminar archivos. Esto, por supuesto, mientras que el apoyo de varias carpetas y las operaciones tales como "obtener la ruta de este nombre de archivo", "obtener la ruta relativa de la ruta absoluta", etc.
Elysium devorado
Creo que, como he dicho, creo una absrtación alrededor del sistema de archivos físico y siempre lo uso (siempre codificando contra la interfaz) en toda su aplicación. luego simplemente use la inyección de dependencia para propagarse a través de su sujeto de prueba. Sé que es un trabajo monótono, pero como programadores tenemos que hacer estas cosas para obtener una separación clara de preocupaciones y permitir la facilidad de
prueba
Realmente no está recibiendo lo que se le pide aquí. Si estoy buscando un sistema de archivos falso, debe ser porque ya hice una abstracción de todo el sistema de archivos en mi aplicación (como se indica en un comentario del OP). Yo solo necesito una aplicación falsa del sistema de archivos para su uso en mis pruebas ..
Elysium devorado
2

ShrinkWrap del proyecto Arquillian busca incluir un sistema de archivos en memoria compatible con NIO

Puede crear un sistema de archivos simple en memoria haciendo lo siguiente:

FileSystem fs = ShrinkWrapFileSystems.newFileSystem(ShrinkWrap.create(GenericArchive.class))
Rob Oxspring
fuente
¿Es compatible con el archivo: // protocolo, no puedo encontrar la documentación ...?
Marco Vasapollo
0

Estaba buscando en Google "Fake java FileSystem" y encontré esta pregunta. Desafortunadamente, esto es todo lo que encontré. Así que escribí este sistema de archivos falso yo mismo: https://github.com/dernasherbrezon/mockfs

Lo estoy usando para simular IOExceptions durante la lectura / escritura de archivos. IOException podría ocurrir, por ejemplo, debido a que "no hay espacio en el disco", lo que es casi imposible de simular por otros medios.

Andrey Rodionov
fuente