Как выполнить модульное тестирование метода Java, который использует ProcessBuilder и Process? - PullRequest
8 голосов
/ 16 октября 2008

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

Псевдо-код:

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;

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

Ответы [ 2 ]

10 голосов
/ 16 октября 2008

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

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

2 голосов
/ 22 июня 2009

В более новых выпусках 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);
    }
}
...