ProcessBuilderとProcessを使用するJavaメソッドを単体テストするにはどうすればよいですか?
-
03-07-2019 - |
質問
ProcessBuilderでプロセスを起動し、その出力をバイト配列にパイプし、プロセスが終了するとバイト配列を返すJavaメソッドがあります。
擬似コード:
ProcessBuilder b = new ProcessBuilder("my.exe")
Process p = b.start();
... // get output from process, close process
このメソッドを単体テストするのに最適な方法は何ですか?信じられないほど素晴らしい JMockit であっても、ProcessBuilderをモックする方法を見つけていません(最終段階です)。 :
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;
現在、このインターフェイスのインスタンスを(コンストラクターで)テストするクラスに渡します。通常は、元の行でデフォルトの実装を使用します。テストする場合は、インターフェイスのモック実装を使用するだけです。魅力のように動作しますが、ここでオーバーインターフェイスしているのではないかと思います...
解決
ock笑されるクラスから身を守る。本当にしたいことをするために(たとえば、外部プロセスがまったく関係していないという事実を隠すために)、またはProcessとProcessBuilder専用にインターフェースを作成します。
ProcessBuilderとProcessが動作することをテストする必要はありません。出力を操作できることのみです。インターフェイスを作成すると、1つの簡単な実装(簡単に検査できます)がProcessBuilderとProcessに委任され、別の実装がこの動作を模倣します。後で、別のプロセスを開始せずに必要なことを実行する別の実装を用意することもできます。
他のヒント
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);
}
}