2008-10-16 10 views
7

Tengo un método de 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.¿Cómo pruebo la unidad de un método Java que usa ProcessBuilder y Process?

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 ir sobre la unidad de pruebas de este método? No he encontrado una manera de burlarse ProcessBuilder (que es la última), incluso con el increíblemente impresionante JMockit, me da una 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) 

¿Alguna idea?


respuesta - Como recomienda Olaf, que terminó refactorización esas líneas a una interfaz

Process start(String param) throws IOException; 

Paso ahora una instancia de esta interfaz en la clase que quería probar (en su constructor), normalmente utilizando una implementación predeterminada con las líneas originales. Cuando quiero probar simplemente utilizo una implementación simulada de la interfaz. Funciona como un amuleto, aunque me pregunto si me estoy sobre-interconectando aquí ...

Respuesta

10

Protégete de las clases que se burlarán. 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 se crea una interfaz, una implementación trivial (que se puede inspeccionar fácilmente) delega a ProcessBuilder y Process, otra implementación se burla de este comportamiento. Más adelante, incluso podría tener otra implementación que haga lo que necesita sin iniciar otro proceso.

2

Con las versiones más recientes de JMockit (0.98+), debería poder simular fácilmente las clases de JRE como Process y ProcessBuilder. Por lo tanto, no hay necesidad de crear interfaces sólo para las pruebas ...

Ejemplo completo (usando 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); 
    } 
} 
+0

¿Qué pasa si usted no desea ejecutar my.exe en absoluto? –

+0

@DavidI. La prueba que se muestra arriba hace eso, es decir, no ejecuta "my.exe". –

+0

Gracias, soy un novato JMockit, así que no entendí al principio. (¡Pero soy un gran fan!) –

Cuestiones relacionadas