14

我有一个 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)

有什么想法吗?


答案- 正如 Olaf 建议的那样,我最终将这些行重构为一个界面

Process start(String param) throws IOException;

我现在将这个接口的一个实例传递给我想要测试的类(在它的构造函数中),通常使用带有原始行的默认实现。当我想测试时,我只需使用接口的模拟实现。就像一个魅力,虽然我想知道我是否在这里过度接口......

4

2 回答 2

14

保护自己免受被嘲笑的课程。为执行您真正想要的操作(例如隐藏完全涉及外部进程的事实)或仅为 Process 和 ProcessBuilder 创建一个接口。

您不想测试 ProcessBuilder 和 Process 是否有效,只是您可以使用它们的输出。当您创建一个接口时,一个简单的实现(可以轻松检查)委托给 ProcessBuilder 和 Process,另一个实现模拟这种行为。稍后,您甚至可能拥有另一个实现,无需启动另一个进程即可满足您的需要。

于 2008-10-16T07:33:20.763 回答
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);
    }
}
于 2009-06-21T22:51:50.700 回答