0

私は次のコードを持っています:

Collection<String> errors = ...;
try (InputStream stream = My.class.getResourceAsStream(resource)) {
   // do stuff
}
catch(IOException ex) {
   errors.add("Fail");
}

私が与える(有効な)入力ストリームが閉じていると思われるときに、Byteman Junit RunnerでIOExceptionをトリガーしようとしています:

@RunWith(BMUnitRunner.class)
public class MyTest {

    private My my = new My();

    @BMRule(
       name = "force_read_error",
       targetClass = "java.io.InputStream",
       targetMethod = "close()",
       action = "throw new IOException(\"bazinga\")"
    )
    @Test
    public void catches_read_error() throws IOException {
       Collection<String> errors = my.foo("/valid-resource-in-classpath");

       assertThat(errors).containsExactly("Fail");
    }
}

私のテストは失敗します: エラーは常に空です。これは明らかに Byteman ルールが実行されていないことを意味します (エージェントによって十分にロードされているため、何が起こっているのかわかりません)。

try-with-resources を介して呼び出された close メソッドで IOException をトリガーするにはどうすればよいですか?

4

1 に答える 1

1

呼び出し時にストリーム オブジェクトのクラスを受け取ったため、ルールは実行されません。

InputStream stream = My.class.getResourceAsStream(resource)

「java.io.InputStream」クラスではありません。これは「java.io.InputStream」を拡張するクラスであり、おそらく「BufferedInputStream」です。

byteman に「java.io.InputStream を拡張する任意のクラスに対してルールをトリガーする」ように指示するには、クラス名の前に「^」を付ける必要があります。

targetClass = "^java.io.InputStream"

この変更には、"java.io.InputStream" を拡張する他のオブジェクトが閉じられたときにもルールがトリガーされるという望ましくない副作用が生じる可能性があります。これを防ぐには、呼び出し元が「My」クラスの「foo」メソッドと一致した場合にのみトリガーされる条件をルールに追加する必要があります。Byteman には、「callerMatches」と呼ばれるヘルパー メソッドがあります (上級チュートリアルも参照してください) 。

あなたの場合の作業条件は次のとおりです。

condition = "callerMatches(\".+My.foo\",true,true)"

BMRule アノテーションとしての完全な Byteman ルール定義は、次のようになります。

@BMRule(
    name = "force_read_error",
    targetClass = "^java.io.InputStream",
    targetMethod = "close()",
    condition = "callerMatches(\".+My.foo\",true,true)",
    action = "throw new java.io.IOException(\"bazinga\")"
)
于 2015-03-25T17:11:11.180 に答える