14

ProcessBuilder で Process を起動し、その出力をバイト配列にパイプして、プロセスが終了するとそのバイト配列を返す Java メソッドがあります。

擬似コード:

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

このメソッドの単体テストを行う最良の方法は何でしょうか? 信じられないほど素晴らしいJMockitを使用しても、 ProcessBuilder をモックする方法が見つかりませんでした (これは最終的なものです)。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 が機能することをテストするのではなく、出力を操作できることだけをテストします。インターフェイスを作成すると、(簡単に検査できる) 1 つの単純な実装が ProcessBuilder と Process に委任され、別の実装がこの動作を模倣します。後で、別のプロセスを開始せずに必要なことを実行する別の実装を作成することさえあるかもしれません。

于 2008-10-16T07:33:20.763 に答える
2

JMockit (0.98+) の新しいリリースでは、Process や ProcessBuilder などの JRE クラスを簡単にモックできるはずです。したがって、テストのためだけにインターフェイスを作成する必要はありません...

完全な例 (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 に答える