2008-10-16 6 views
7

У меня есть метод Java, который запускает процесс с ProcessBuilder и транслирует его вывод в массив байтов, а затем возвращает его массив байтов, когда процесс завершен.Как я могу протестировать метод Java, который использует ProcessBuilder и Process?

Псевдо-код:

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

Что бы быть лучшим способом пойти о модульном тестировании этого метода? Я не нашел способ поиздеваться ProcessBuilder (это окончательный), даже с невероятно удивительным JMockit, это дает мне 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) 

Любые мысли?


Ответ - В соответствии с рекомендациями Олафа, я закончил рефакторинг этих строк к интерфейсу

Process start(String param) throws IOException; 

теперь передать экземпляр этого интерфейса в класс я хотел проверить (в конструкторе), обычно используя реализацию по умолчанию с исходными строками. Когда я хочу протестировать, я просто использую макетную реализацию интерфейса. Работает как шарм, хотя я действительно задаюсь вопросом, не перепутал ли я здесь ...

ответ

10

Защитите себя от классов, чтобы их издевались. Создайте интерфейс для того, чтобы делать то, что вы действительно хотите (например, скрываете тот факт, что внешние процессы задействованы вообще) или только для Process и ProcessBuilder.

Вы не хотите проверять, что ProcessBuilder и Process работают, только чтобы вы могли работать с их выходом. Когда вы создаете интерфейс, одна тривиальная реализация (которую можно легко проверить) делегирует ProcessBuilder и Process, другая реализация издевается над этим поведением. Позже у вас может быть даже другая реализация, которая делает то, что вам нужно, не запустив другой процесс.

2

С более новыми версиями JMockit (0.98+) вы должны быть в состоянии легко высмеять классы JRE, такие как Process и ProcessBuilder. Таким образом, нет необходимости создавать интерфейсы только для тестирования ...

Полный пример (с использованием 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

Что делать, если вы не хотите, чтобы выполнить my.exe вообще? – 2015-05-28 20:07:38