プロが教えるわが家の防犯対策術!

JUnit関連の少しコアな話になります。
JUnitではデフォルトでは、実行する際初期処理としてまずテストクラス内のテストメソッドの数だけテストクラスをインスタンス化し、その後各テストメソッドを実行していく、という仕様になっているようです。そしてかつ、各インスタンスはテストクラス内のすべてのテストメソッドが終了するまでインスタンスの破棄は行わないようです。

上記の仕様であるはずだと言う根拠は、テストクラスにコンストラクタを作成し、そこにsysoutを記述することにより確認をしました。

上記の仕様であることが主原因で、Out of Memoryが発生してしまいます。
他にそうなってしまう原因はいくつかあって
・Springを利用していて初期化にメモリを結構使う
・テスト対象のクラスが複雑でテストメソッドの数が多くなる
・パソコンの物理メモリに限界がある
・DJUnitでカバレッジを調査することもあり、またテスティングペアの名前は統一したいので、テスト対象クラスとテストクラスを1対1に対応させたい。
などが挙げられます。VMの実行メモリを大きくしたり、テストクラスを分割してしまうなどの対処療法を行ってきましたが、何とか主原因をつぶす方法は無いものかと質問をした次第です。

(その他、使用しなくなったオブジェクトにnullをセットしたり明示的にgcの実行を指示する等の苦肉の策を行いましたが、ほとんど影響しませんでした)


前置きが長くなりましたが質問は、JUnitでテストを行う際、テストクラス内のテストメソッドの数だけインスタンス化しているものを、あるテストメソッドを実行する直前にインスタンス化し、そのテストメソッドが終了したらそのインスタンスを破棄するような設定はないのか、あればその方法を教えてほしい、ということになします。

だいぶ分かりにくい説明かもしれませんが…。
以上よろしくお願いします。

A 回答 (1件)

やっつけで試してみたら成功しました。



JUnitのソースを変更します。

変更するソースは「junit.framework.TestSuite」です。

1.クラスに内部クラス「LazyInstance 」を追加

static class LazyInstance implements Test {
 Class clazz;
 String name;
 Test instance;

 LazyInstance(Class clazz, String name) {
  this.clazz = clazz;
  this.name = name;
 }

 public int countTestCases() {
  return 1;
 }

 public void run(TestResult result) {
  if (instance == null) {
   instance = realCreateTest(clazz,name);
  }
  instance.run(result);
 }
}

2.メソッドcreateTestの中身をコピーしたstaticメソッド「realCreateTest」を追加
(長いので略しますが、createTestメソッドを丸々コピーしてメソッド名だけ「realCreateTest」に変えたものです)

3.メソッドcreateTestを以下のように修正

static public Test createTest(Class theClass,String name) {

 LazyInstance li = new lazyInstance(theClass,name);
 return li;
 }

この回答への補足

記述の通りでできました。
エクリを使用していたため、複数のJUnitjarが存在していたのに気づかず、1つだけ消してそれで全て消したつもりになっていたことが原因でした。

kazsharpさんありがとうございました。

補足日時:2006/02/12 13:19
    • good
    • 0
この回答へのお礼

なんかすごいですね…。
ライブラリの中身を変更するという考えは思い浮かびませんでした。

…で、試してみたのですが、うまく行きませんでした。コンストラクタにシスアウトを記述するとテストメソッド実行前にコンストラクタがテストメソッド分呼び出されていました。

私の記述ミスである可能性もあるので、もう少しゆっくり試してみます。ありがとうございました。


ちなみに困っていた現象は
>Springを利用していて初期化にメモリを結構使う
という部分で、使用するクラスをすべてインスタンスとして持つApplicationContextと呼んでいるインスタンスが10MBを超え、テストメソッドが50を超える場合に、実行メモリを500MBにしてもメモリが不足したという現象でした。

で、実はこの件に関しては、static変数に記述し、スレッドをたくさん作られてもインスタンスが1つしか存在しないようにすることにより回避することができました。

しかし、今回の質問の趣旨のJUnitの遅延初期化の話も将来的に使うかもしれない部分であるので、もう少し調べてみたいと思っています。

お礼日時:2006/02/10 15:41

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!