Domanda

Ho un metodo Java che avvia un processo con ProcessBuilder e ne convoglia l'output in un array di byte, quindi restituisce il suo array di byte al termine del processo.

pseudo-codice:

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

Quale sarebbe il modo migliore per testare l'unità di questo metodo? Non ho trovato il modo di deridere ProcessBuilder (è definitivo), anche con l'incredibile JMockit , mi dà 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)

Qualche idea?


Risposta - Come raccomandato da Olaf, ho finito per refactoring quelle linee in un'interfaccia

Process start(String param) throws IOException;

Passo ora un'istanza di questa interfaccia nella classe che volevo testare (nel suo costruttore), normalmente usando un'implementazione predefinita con le linee originali. Quando voglio fare un test, utilizzo semplicemente un'implementazione fittizia dell'interfaccia. Funziona come un incantesimo, anche se mi chiedo se sto interfacciando troppo qui ...

È stato utile?

Soluzione

Proteggiti dalle classi da deridere. Crea un'interfaccia per fare ciò che vuoi veramente (ad esempio nascondere il fatto che i processi esterni sono coinvolti) o solo per Process e ProcessBuilder.

Non vuoi testare che ProcessBuilder e Process funzionano, ma solo che puoi lavorare con il loro output. Quando si crea un'interfaccia, un'implementazione banale (che può essere ispezionata facilmente) delega a ProcessBuilder e Process, un'altra implementazione prende in giro questo comportamento. In seguito potresti persino avere un'altra implementazione che fa ciò di cui hai bisogno senza avviare un altro processo.

Altri suggerimenti

Con le versioni più recenti di JMockit (0.98+) dovresti essere in grado di deridere facilmente le classi JRE come Process e ProcessBuilder. Quindi, non è necessario creare interfacce solo per i test ...

Esempio 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);
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top