Question

J'ai une méthode Java qui démarre un processus avec ProcessBuilder et dirige sa sortie dans un tableau d'octets, puis renvoie son tableau d'octets à la fin du processus.

Pseudo-code:

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

Quel serait le meilleur moyen de tester cette méthode avec l’unité? Je n'ai pas trouvé de moyen de se moquer de ProcessBuilder (c'est final), même avec l'incroyablement impressionnant JMockit , cela me donne la mention 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)

Avez-vous des idées?

Réponse : comme Olaf le recommandait, j'ai finalement refactoré ces lignes sur une interface

Process start(String param) throws IOException;

Je passe maintenant une instance de cette interface dans la classe que je voulais tester (dans son constructeur), en utilisant normalement une implémentation par défaut avec les lignes d'origine. Lorsque je veux tester, j'utilise simplement une implémentation fictive de l'interface. Fonctionne comme un charme, bien que je me demande si je suis trop interfacé ici ...

Était-ce utile?

La solution

Protégez-vous des cours pour vous moquer. Créez une interface pour faire ce que vous voulez vraiment (par exemple, en masquant le fait que des processus externes sont impliqués), ou uniquement pour Process et ProcessBuilder.

Vous ne voulez pas tester que ProcessBuilder et Process fonctionnent, mais seulement que vous pouvez utiliser leur sortie. Lorsque vous créez une interface, une implémentation triviale (pouvant être facilement inspectée) est déléguée à ProcessBuilder et Process, une autre implémentation simule ce comportement. Plus tard, vous pourriez même avoir une autre implémentation qui fait ce dont vous avez besoin sans démarrer un autre processus.

Autres conseils

Avec les nouvelles versions de JMockit (0.98+), vous devriez pouvoir facilement simuler des classes JRE telles que Process et ProcessBuilder. Donc, pas besoin de créer des interfaces juste pour les tests ...

Exemple complet (avec 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);
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top