コマンドラインからスクリプトを実行し、さらに処理するために結果を取得するために Runtime.getRuntime() が使用されるクラスがあります。
しかし、このクラスの JUnit を作成すると、この Runtime.getRuntime().exec() をモック/回避する方法が見つかりません。
EasyMock や PowerMock 、またはMockito以外のモック API は使用できません。
コード カバレッジに影響しているため、この問題を解決する方法を教えてください。
コマンドラインからスクリプトを実行し、さらに処理するために結果を取得するために Runtime.getRuntime() が使用されるクラスがあります。
しかし、このクラスの JUnit を作成すると、この Runtime.getRuntime().exec() をモック/回避する方法が見つかりません。
EasyMock や PowerMock 、またはMockito以外のモック API は使用できません。
コード カバレッジに影響しているため、この問題を解決する方法を教えてください。
リファクタリングする必要があります。Runtime.getRuntime().exec()
別のクラスに抽出します。
public class Shell {
public Process exec(String command) {
return Runtime.getRuntime().exec(command);
}
}
これで、テスト対象のクラスになんらかの方法でgetRuntime()
明示的にShell
クラスを挿入するようになりました。
public class Foo {
private final Shell shell;
public Foo(Shell shell) {
this.shell = shell;
}
//...
shell.exec(...)
}
JUnitテストでは、モックShell
クラスをコンストラクターに渡すことで、モッククラスを挿入するだけです。
@Mock
private Shell shellMock;
new Foo(shellMock);
補足:はい、私は1つの実装でインターフェースを作成していません。Shell
あなたは気にしますか?Mockitoはそうではありません。ボーナス:正しいプロセスが呼び出されたかどうかを確認できるようになりました:
verify(shellMock).exec("/usr/bin/gimp");
Tomasz Nurkiewicz が素晴らしい回答を提供してくれました。しかし、代替手段があります。
Runtime.getRuntime()
テストしているクラスの独自のメソッドに移動できます。次に、Mockito スパイでテストします。Mockito スパイでは、この特定のメソッドを mock を作成するバージョンでオーバーライドしてから、Runtime
好きなことを行うことができます。
ただし、Tomasz のアプローチはよりクリーンであり、徹底的にお勧めします。Powermockに頼らずに、それを行う別の方法があると言いたかっただけです。
サブクラス化とオーバーライドを使用しました (Michael C. Feathers の著書「Working effective with legacy code」で説明されているように)
次のコードがあるとします。
public class CannotChange{
public CannotChange(){}
public void TryingToTest() throws IOException {
...
Process proc = Runtime.getRuntime().exec("command");
...
}
}
ランタイム コードを保護されたメソッドに抽出します。
public void TryingToTest() throws IOException {
...
Process proc = execute("command");
...
}
protected Process execute(string command){
return Runtime.getRuntime().exec(command);
}
次に、テスト クラスで、CannotChange クラスを拡張し、execute をオーバーライドするクラスを作成します。
public class CannotChangeTest{
private class CannotChangeForTesting extends CannotChange{
public CannotChangeForTesting(){ super(); }
@Override
public Process execute(String command){
return null; //or a mocked object
}
}
@Test
public void TestMethod(){
CannotChange cannotChange = new ForTestCannotChange();
cannotChange.TryingToTest();
}
}