バイトコード・インジェクション・ツール BytemanとJUnitの連携
再現が難しい例外*1を、Bytemanで発生させて確認したりしている。最近、1.5がリリースされて、JUnitと連携できるようになっていたので試してみた。
Byteman - JBoss Community
Byteman 1.5.0 JUnit Integration Makes Fault Injection Simple
Sample.returnTrue()は、trueを返すだけのメソッド。SampleTest.testReturnTrue()の@BMRuleアノテーションで、例外を投げるよう定義している。
Sample.checkNumberPrivate(int i)はprivateメソッドなので、直接テストコードから呼び出せないが、@BMRuleアノテーションで同じく例外を投げるよう定義している。
どちらもRuntimeExceptionが投げられて、テストは成功する。
Sample.java
public class Sample { public boolean returnTrue() { return true; } public boolean checkNumber(int i){ return checkNumberPrivate(i); } private boolean checkNumberPrivate(int i) { if (i > 0) { System.out.println(i); return true; } else { throw new RuntimeException(); } } }
SampleTest.java
@RunWith(BMUnitRunner.class) public class SampleTest { @BMRule(name = "throw runtime exception", targetClass = "sample.Sample", targetMethod = "returnTrue", condition = "true", action = "throw new RuntimeException()") @Test(expected = RuntimeException.class) public void testReturnTrue() throws Exception { Sample s = new Sample(); s.returnTrue(); } @BMRule(name = "throw runtime exception 2", targetClass = "sample.Sample", targetMethod = "checkNumberPrivate(int)", condition = "true", action = "throw new RuntimeException()") @Test(expected = RuntimeException.class) public void testCheckNumber() throws Exception { Sample s = new Sample(); s.checkNumber(1); } }
今のところ私は、JUnit連携は使ってないし、任意の場所で例外投げたり、スタックトレースを出力したり、といった使い方しかしてないが、もう少し深く掘り下げてみようかな。
最初Eclipseでうまく動かなくて難儀したが、単に環境変数BYTEMAN_HOMEも、システムプロパティorg.jboss.byteman.homeも設定していなかっただけだった。正確には、zshrcにはBYTEMAN_HOMEを設定していたんだが、~/.MacOSX/environment.plistに設定していなかったから、eclipseに環境変数が渡ってなかった。長年Macを使っているのに、environment.plistって知らんかった…。
*1:と思ったが、実際使ったケースではそうでもなかった。