Pregunta

Tengo un método Java que inicia un Proceso con ProcessBuilder y canaliza su salida en una matriz de bytes, y luego devuelve su matriz de bytes cuando el proceso finaliza.

Pseudo-código:

ProcessBuilder b = new ProcessBuilder("my.exe")
Process p = b.start();
... // get output from process, close process

¿Cuál sería la mejor manera de hacer una prueba unitaria de este método? No he encontrado una manera de burlarme de ProcessBuilder (es definitivo), incluso con el increíblemente increíble JMockit , me da un NoClassDefFoundError :

java.lang.NoClassDefFoundError: test/MockProcessBuilder
    at java.lang.ProcessBuilder.<init>(ProcessBuilder.java)
    at mypackage.MyProcess.start(ReportReaderWrapperImpl.java:97)
    at test.MyProcessTest.testStart(ReportReaderWrapperImplTest.java:28)

¿Algún pensamiento?


Respuesta : como recomendó Olaf, terminé refactorizando esas líneas en una interfaz

Process start(String param) throws IOException;

Ahora paso una instancia de esta interfaz a la clase que quería probar (en su constructor), normalmente usando una implementación predeterminada con las líneas originales. Cuando quiero probar simplemente uso una implementación simulada de la interfaz. Funciona como un amuleto, aunque me pregunto si estoy haciendo una interfaz excesiva aquí ...

¿Fue útil?

Solución

Protégete de las clases para que te burlen. Cree una interfaz para hacer lo que realmente desea (por ejemplo, ocultar el hecho de que los procesos externos están involucrados) o solo para Process y ProcessBuilder.

No desea probar, que ProcessBuilder y Process funcionan, solo que puede trabajar con su salida. Cuando creas una interfaz, una implementación trivial (que se puede inspeccionar fácilmente) delega en ProcessBuilder y Process, otra implementación se burla de este comportamiento. Más adelante, es posible que incluso tenga otra implementación que haga lo que necesita sin iniciar otro proceso.

Otros consejos

Con las nuevas versiones de JMockit (0.98+) debería poder simular fácilmente clases de JRE como Process y ProcessBuilder. Por lo tanto, no es necesario crear interfaces solo para probar ...

Ejemplo completo (utilizando JMockit 1.16):

public class MyProcessTest
{
    public static class MyProcess {
        public byte[] run() throws IOException, InterruptedException {
            Process process = new ProcessBuilder("my.exe").start();
            process.waitFor();

            // Simplified example solution:
            InputStream processOutput = process.getInputStream();
            byte[] output = new byte[8192];
            int bytesRead = processOutput.read(output);

            return Arrays.copyOf(output, bytesRead);
        }
   }

    @Test
    public void runProcessReadingItsOutput(@Mocked final ProcessBuilder pb)
        throws Exception
    {
        byte[] expectedOutput = "mocked output".getBytes();
        final InputStream output = new ByteArrayInputStream(expectedOutput);
        new Expectations() {{ pb.start().getInputStream(); result = output; }};

        byte[] processOutput = new MyProcess().run();

        assertArrayEquals(expectedOutput, processOutput);
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top