2008-10-16 2 views
7

Ich habe eine Java-Methode, die einen Prozess mit ProcessBuilder startet und seine Ausgabe in ein Byte-Array pipettiert und dann das Byte-Array zurückgibt, wenn der Prozess beendet ist.Wie teste ich Unit-Test eine Java-Methode, die ProcessBuilder und Process verwendet?

Pseudo-Code:

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

Was wäre der beste Weg, Einheit zu gehen über diese Methode zu testen?

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) 

Irgendwelche Gedanken: Ich habe nicht einen Weg zu verspotten Process (es ist endgültig), auch mit dem unglaublich genial JMockit, es gibt mir ein NoClassDefFoundError gefunden?


Antwort - Als Olaf empfohlen, landete ich

Process start(String param) throws IOException; 

ich jetzt eine Instanz dieser Schnittstelle in die Klasse übergeben I (in seinem Konstruktor testen wollte diese Zeilen an eine Schnittstelle Refactoring up), wobei normalerweise eine Standardimplementierung mit den ursprünglichen Zeilen verwendet wird. Wenn ich testen will, verwende ich einfach eine Pseudo-Implementierung der Schnittstelle. Funktioniert wie ein Zauber, obwohl ich mich wundere, wenn ich hier über die Schnittstelle bin ...

Antwort

10

Schild sich von den Klassen zu verspotten. Erstellen Sie eine Schnittstelle, um entweder das zu tun, was Sie wirklich wollen (z. B. das Ausblenden der Tatsache, dass externe Prozesse überhaupt beteiligt sind) oder nur für Process und ProcessBuilder.

Sie möchten nicht testen, dass ProcessBuilder und Process arbeiten, nur dass Sie mit ihrer Ausgabe arbeiten können. Wenn Sie eine Schnittstelle erstellen, wird eine triviale Implementierung (die leicht überprüft werden kann) an ProcessBuilder und Process delegiert, eine andere Implementierung verhöhnt dieses Verhalten. Später haben Sie möglicherweise noch eine andere Implementierung, die das tut, was Sie brauchen, ohne einen weiteren Prozess zu starten.

2

Mit neueren Versionen von JMockit (0.98+) sollten Sie in der Lage sein, JRE-Klassen wie Process und ProcessBuilder einfach nachzuahmen. Also, keine Notwendigkeit zu schaffen Schnittstellen nur zum Testen ...

Voll Beispiel (unter Verwendung von 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

Was passiert, wenn Sie nicht my.exe überhaupt ausführen wollten? –

+0

@DavidI. Der oben gezeigte Test macht das, dh es führt "my.exe" nicht aus. –

+0

Danke, ich bin ein JMockit-Neuling, also habe ich das zunächst nicht verstanden. (Aber ich bin ein großer Fan!) –

Verwandte Themen