Как выполнить модульное тестирование метода Java, использующего ProcessBuilder и Process?

StackOverflow https://stackoverflow.com/questions/207636

Вопрос

У меня есть метод 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;

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

Это было полезно?

Решение

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

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

Другие советы

В более новых версиях 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);
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top