2010-12-13 8 views
9

Estoy usando una biblioteca de terceros que básicamente crea un directorio de salida con diferentes tipos de archivos y subdirectorios dentro. Me gustaría poder escribir pruebas unitarias para confirmar que la salida es correcta.¿Se puede crear un disco RAM de Java para ser utilizado con la API java.io. *?

Me gustaría poder utilizar la lib con un disco RAM, de modo que nada de lo que la biblioteca haga toca las placas de disco reales de ninguna manera. La idea es hacer las pruebas muy rápido para ejecutar y limpiar (¿soltar el disco RAM?).

Las dos opciones más destacadas disponibles para mí son Commons VFS y JSR 203. El primero no me sirve porque quiero que las cosas funcionen de manera transparente utilizando la API java.io. * y no las clases VFS de Commons. Lo último no funciona porque tengo que conformarme con JDK 6 (se supone que es parte de JDK 7) y no sé si funcionará sin problemas con java.io. * de todos modos (no lo haría). puedes contar con ello).

También hay other soluciones, pero no puedo usarlas por la misma razón que no puedo usar Commons VFS. Los simulacros están fuera de discusión debido a la complejidad de la biblioteca en cuestión.

En mi máquina Linux, puedo crear fácilmente una unidad RAM y usar la API java.io. * de la misma manera que lo haría con los archivos en el disco. La cuestión es que quiero que sea multiplataforma y, más específicamente, que la configuración del disco sea parte del procedimiento de prueba, en lugar de algo externo.

Entonces, ¿hay alguna forma de registrar una unidad de RAM en Java que pueda utilizarse con la API java.io. * estándar?

+3

Por qué no mirar fuera de Java. Cree un disco RAM en el nivel del sistema operativo (existen herramientas para Windows y Linux) y simplemente dele a su biblioteca esa ruta. –

+4

Ya expliqué por qué: idealmente quería que el procedimiento fuera independiente de la plataforma. Además, preferiría que cualquier código necesario esté en Java, en lugar de escribir scripts externos para configurar y disponer un disco RAM en un entorno u otro. –

+0

¿Has encontrado una solución? Para Java 7 o Java 8. – Jus12

Respuesta

6

Entonces, ¿hay alguna forma de registrar una unidad de RAM en Java que se pueda utilizar con la API java.io. * estándar?

No con una Java 6 o una JVM anterior. Java 6 y versiones anteriores no proporcionan ningún SPI para registrar sistemas de archivos o tipos de sistemas de archivos. Entonces, implementar una RAM FS que una aplicación usaría como una FS normal implicaría modificar el comportamiento de un número de clases java.io.*.

Creo que lo mejor que podría hacer sería utilizar una RAM FS implementada por el sistema operativo host. Debería poder acceder a eso desde Java como si fuera un sistema de archivos normal. Sin embargo, E/S sería conllevará una llamada al sistema, por lo que no sería tan rápido como si el sistema de archivos RAM se mantuviera en la memoria administrada de JVM.

+0

Gracias por una respuesta clara y precisa. Tal como está, probablemente rebajaré las pruebas a pruebas de integración y trabajaré con ellas. –

4

Teóricamente Stephen tiene razón. Pero te puedo sugerir un truco. Puede implementar su propio FileInputStream y FileOutputStream y ponerlos en bootclasspath. Su implementación implementará, por ejemplo, open(), read() y readBytes() (que son métodos nativos en FileInputStream).

Esta es una solución java pura para su problema. Su desventaja es que debe ejecutar sus pruebas en una instancia separada de JVM.

+2

No es realmente "Java puro" en la medida en que modificar las clases del sistema no está dentro del alcance de las especificaciones de Java, es decir, esto podría funcionar en algunas implementaciones de Java, pero no funcionará en otras. –

+2

Según tengo entendido, él no puede hacer eso, incluso si lo desea. Él dice * "[t] él luego no lo corta porque tengo que conformarme con JDK 6" *. Si reemplaza las clases 'java.io. *' con versiones personalizadas, entonces ya no es Java 6. (De hecho, ¡técnicamente no es Java en absoluto!) –

+2

además, el reemplazo de las clases estándar de Java definitivamente NO es un "Java puro"; vea este enlace - http://www.javacoffeebreak.com/faq/faq0006.html. Dependiendo de una JVM pirateada, automáticamente el código no es portátil y, por lo tanto, no es "pura Java", IMO. –

1

El problema básico que está tratando de superar es que las API originales java.io no son flexibles (todas se refieren a clases concretas). La única forma en que puede poner diferentes funcionalidades, por ejemplo java.io.File, es ampliando la clase base.

Ampliar las clases después de que están diseñadas puede ser un mal diseño (basta con mirar la clase Properties) - por lo que probablemente no encuentre una biblioteca que lo haga.

Nada le impide extender la clase java.io.File usted mismo, y proxy todos los métodos para, por ejemplo, un FileObject de la API de VFS de Commons.

Editar: Sin embargo, hay cosas que probablemente se producirá un error en virtud del mismo - por ejemplo, utilizando los File constructores que toman un padre File.

Editar 2: Bueno, me gustaría comenzar con algo así:

public class VirtualFile extends java.io.File { 
    public static VirtualFile fromFile(File file) { 
     if (file instanceof VirtualFile) { 
      return (VirtualFile) file; 
     } else { 
      FileSystemManager fsm = new DefaultFileSystemManager(); 
      return fsm.toFileObject(file); 
     } 
    } 

    private final org.apache.commons.vfs.FileObject mProxyFileObject; 


    public VirtualFile(FileObject proxy) { 
     super("/tmp/xxxx"); // That part needs some work to be cross-platform. 
          // However, such a construction will completely 
          // destroy the expectations that other classes 
          // have about what a File is. 
     mProxyFileObject = proxy; 
    } 

    public VirtualFile(VirtualFile parent, String child) { 
     this(parent.mProxyFileObject.resolveFile(child)); 
    } 

    public VirtualFile(File parent, String child) { 
     this(fromFile(parent), child); 
    } 

    @Override 
    public boolean canExecute() { 
     throw new UnsupportedOperationException(); 
    } 

    @Override 
    public boolean canRead() { 
     try { 
      return mProxyFileObject.isReadable(); 
     } catch (FileSystemException fse) { 
      // FileSystemException is not a Runtime Exception :(
      throw new RuntimeException(fse); 
     } 
    } 

    // Override ALL public methods to throw Exceptions; 
    // implement or mock only the methods that you need. 
} 

En cuanto a por qué el File(File, String) constructor no funcionaría con esa configuración: el constructor no espera una implementación de File para romper el contrato de la clase, lo cual hacemos cuando llamamos al super("/tmp/xxxx"). (Y no podemos evitar romper el contrato de la clase, porque los archivos virtuales con los que queremos trabajar no tienen un equivalente simple File)

Así que, ahí está, requeriría un poco de trabajo no trivial, y hay una posibilidad significativa de que la biblioteca no funcione como se espera de todos modos.

+0

¿Podría explicarnos un poco sobre cómo haría las llamadas proxy de java.io.File a, p. un FileObject y cuál sería el problema con el constructor File (File)? –

+0

Gracias por una aclaración bastante extensa, Jean. Lamentablemente, no veo cómo mejora la situación en comparación con simplemente usar Commons VFS. La biblioteca de terceros que estoy usando no sabe de una clase VirtualFile y (por supuesto) no la usaría. Si fue escrito para usar una capa de abstracción como la que describiste, eso podría haberme dado algo con lo que trabajar.Parece que voy a estar atascado con los archivos en el disco, por el momento. –

+0

@Tomislav: No sabía cuánto control tenías en la biblioteca, o tal vez podrías proporcionar un "Archivo" básico a la biblioteca. –

Cuestiones relacionadas