2012-06-24 1 views
6

Javaの弱参照をテストする適切な方法は何ですか?WeakReferenceのテスト

私の最初のアイデアは、次の操作を実行することです:

public class WeakReferenceTest { 

    public class Target{ 
     private String value;  

     public Target(String value){ 
      this.value = value; 
     }  
     public String toString(){ 
      return value; 
     } 
    } 

    public class UsesWeakReference{  
     WeakReference<Target> reference; 

     public UsesWeakReference(Target test){ 
      reference = new WeakReference<Target>(test); 
     }  
     public String call(){ 
      Target test = reference.get(); 
      if(test != null){ 
       return test.toString(); 
      } 
      return "empty"; 
     } 
    } 

    @Test 
    public void testWeakReference(){  
     Target target = new Target("42"); 

     UsesWeakReference usesWeakReference = new UsesWeakReference(target);  
     WeakReference<Target> triggerReference = new WeakReference<Target>(target);  
     assertEquals("42", usesWeakReference.call()); 

     target = null;  
     while(triggerReference.get() != null){ 
      System.gc(); 
     } 

     assertEquals("empty", usesWeakReference.call());  
    }  
} 

私はそれが異なるJVM上で異なる動作をすることができますことを理解し、私はアプローチについて持っている予約がにSystem.gc()を使用しています。

答えて

5

リファレンスタイプを使用するコードをテストするための100%防爆方法はありません。参照オブジェクトの動作は、GCがいつ実行されるかによって異なり、100%確実にGCを実行する方法はありません。

あなたができる最善のである:System.gc()こと、それはイベントで失敗しないように

  • あなたがテストを実行するときに設定し、右のJVMオプションがあり、チェック、および
  • は、あなたのテストを書きますまたははテストを無効にしたりスキップしたり、テストの失敗を無視したりしないでください。

(あなたがSystem.gc()は、メモリが呼び出しの前後に使用されているどのくらいのを見て、無視されていることを検出することができるはずです。Runtime.totalMemory()を呼び出すことによって)


実際には、別のがあります"溶液"。あなたの単体テストで膨大な量のゴミを生成させてください...ガベージコレクションを引き起こすことを保証するのに十分です。 (良い考えではない、IMO。)

+0

答えをいただきありがとうございます...私の見解を立証します。 –

3

新しい質問への新しい答え; WeakReferenceの対象がnullになると、テスト対象のクラスが非常に具体的なことを確認するために単体テストを作成したいと思います。

私は最初に、参照先をnullに設定する簡単なテストケースを書きました。 System.gc()を呼び出します。興味深いことに:少なくとも私の日食では、それは私のweakRefernce.get()がnullを返すために「十分に良い」ものでした。

しかし、これは、将来にわたってこのユニットテストを実行するすべての将来の環境で動作するかどうかを知っています。

ので、いくつかのより多くの思考の後:

@Test 
public void testDeregisterOnNullReferentWithMock() { 
    @SuppressWarnings("unchecked") 
    WeakReference<Object> weakReference = EasyMock.createStrictMock(WeakReference.class); 
    EasyMock.expect(weakReference.get()).andReturn(null); 
    EasyMock.replay(weakReference); 
    assertThat(weakReference.get(), nullValue()); 
    EasyMock.verify(weakReference); 
} 

はあまりにも、うまく動作します。

意味:この問題に対する一般的な答えは、オブジェクトのWeakReferenceを作成するファクトリです。したがって、プロダクションコードをテストしたいとき。あなたはそれにモックされた工場を提供します。その工場はWeakReferenceオブジェクトを嘲笑します。その弱い参照オブジェクトの振る舞いを完全に制御できます。

「フルコントロール」は、よりもはるかに優れており、とすれば、GCがあなたが望んでいることを多分行うことができます。

+0

ここでは、GCが完全に決定論的でも制御可能でもないので、モッキングが最適です。 – kerner1000

+0

非常に正しい - もっと明確にするために別の段落を追加しました。記録のために:あなたの目に合ったアップヴォートを作るために何かできることはありますか? – GhostCat

+0

私はそれがすでにかなり明確だと思います。自分のタイプの別のコンストラクタを作成しなければなりませんでした。私は嘲笑されたWeakReference(主にクリーンコードをテストするコンストラクタですか?たぶん、WeakReferenceを模擬することは再現可能なテストには最適ですが、現実的ではありません。つまり、信頼性の低いGCの動作を明示的にテストしたい場合は、最適な方法ではないかもしれません。 (upvoteのおかげで;)) – kerner1000

関連する問題