連鎖呼び出しのためのモックまたはスタブ

protected int parseExpire(CacheContext ctx) throws AttributeDefineException {
    Method targetMethod = ctx.getTargetMethod();
    CacheEnable cacheEnable = targetMethod.getAnnotation(CacheEnable.class);
    ExpireExpr cacheExpire = targetMethod.getAnnotation(ExpireExpr.class);
   //check for duplicate setting
    if (cacheEnable.expire() != CacheAttribute.DO_NOT_EXPIRE && cacheExpire != null) {
        throw new AttributeDefineException("expire are defined both in @CacheEnable and @ExpireExpr");
    }
   //expire time defined in @CacheEnable or @ExpireExpr
    return cacheEnable.expire() != CacheAttribute.DO_NOT_EXPIRE ? cacheEnable.expire() : parseExpireExpr(cacheExpire, ctx.getArgument());
}

それはテストする方法ですが、

Method targetMethod = ctx.getTargetMethod();
CacheEnable cacheEnable = targetMethod.getAnnotation(CacheEnable.class);

私は3つのCacheContext、MethodとCacheEnableをモックする必要があります。 テストケースをもっと簡単にするという考えはありますか?

46

3 答え

101
追加された
答えの先頭にあるリンクが壊れています。
追加された 著者 ajb,
しかし、それはいつも機能が羨ましいですか?大きなデータをメモリにまとめることができます。私はこのツリーからデータを読み込み、そのツリー上で操作を行う他のクラスを持っています。それらをテストするために、私はdtoを模倣する必要があります - BTW、私は実際のdtoを作成することができますが、それはちょっと面倒です - 深いスタブが本当にこの場合私を助けます。ここで何かが恋しい?コードを改善することはできますか?
追加された 著者 Arash,
@ Lunivoreフェアポイント。それを行うレベルは1つ程度は許容されるかもしれませんが、私はその方法がおそらく広く虐待されていることを理解しています。私はそれが非推奨の候補かどうか疑問に思います。
追加された 著者 Magnilex,
@Lunivore著者は深いスタブがレガシーコードにのみ使われるべきだと述べている公式ソースを指していますか?
追加された 著者 Magnilex,
@Arashそれは必ずしも機能羨望ではありません。あなたのケースでは、モデルが特定のDTOでパーシスタンスレイヤーに表示される何らかのMVPパターンを作成します。今ではDTOだけでなく、豊かなオブジェクトを持っています。 MVPのようなパターンは、UIの永続性にも適用できます!
追加された 著者 Lunivore,
@ VivekKothari Mockitoチームにそれを提出することはできますか? github.com/mockito/mockito/issues
追加された 著者 Lunivore,
@Samiこれは華やかな小さなツールのように見えます。私はReekの前に来たことはありません。そして、なんと素晴らしい名前...:D
追加された 著者 Lunivore,
うんあなたの次のレガシーコードステップが、メソッドの1つを適切な場所に移動することです(問題を完全に排除しますが、後で多量の修正を必要とするこのようなやり方を引き起こします)。
追加された 著者 Lunivore,
@Magnilexそれは実際には正式な情報源である です。のように、ソースコード。 "ほとんどのシナリオでは模擬試験を返す模擬試験は間違っていることに注意してください。警告:この機能は通常のクリーンなコードではほとんど必要ありません。レガシーコードのままにしておきます。デモータの法則に違反して何か意味のあるヒントを返すか、価値オブジェクト(よく知られている反パターン)を嘲笑するために、モックを返すためのモックを嘲笑して、モックを返す(...)。 github.com/mockito/mockito/ blob/master/src/main/java/org /… (ほとんど1393行目)
追加された 著者 Lunivore,
@Magnilexレガシーコードに関するラッピングテストは、それを安全にリファクタリングできる重要な部分です。より洗練されたコードベースへの中間的なステップとしてそれを持つことには何も問題ありません。
追加された 著者 Lunivore,
@Magnilexそれは、私は実際には、私が嘲笑したくない内部ハッシュマップに転送するいくつかのメソッドと複雑なインターフェイスをバックアップするために、現時点ではRETURNS_DEEP_STUBSを使用しているとKotlinと "by"キーワードを使用して...最近では、それ以上の用途があるかもしれません。
追加された 著者 Lunivore,
もちろんあなたが意味する Mockito :)
追加された 著者 Lunivore,
@ajbありがとうございました。一定。
追加された 著者 Lunivore,
まあ、Szczepanは、EasyMockを使う代わりに私と他の人たちが手で自分のモックを展開しているのを見て、Mockitoを作ったので、私はMockitoが好きです。しかし、彼はそれを行うためにEasyMockを分割したので、そういう理由で、EasyMockは素晴らしいです。私たちは巨人の肩に立つ...
追加された 著者 Lunivore,
これは面白いです、私はupvoted。しかし、単純に Foo foo = mock(Foo.class);を使用することはできません。バーバー=モック(Bar.class); when(foo.getBar())。then返します(bar); when(bar.getName())。then return( "deep") '。私の目には、読みやすく、 "DEEP"スタブの概念を理解する必要はありません。 (Btw、私はMockitoが好きです。)
追加された 著者 cdunn2001,
Feture Envyの定義はここに移動しました: github.com/troessner/reek /blob/master/docs/Feature-Envy.md
追加された 著者 Sammi,
チェーンの1つがジェネリック型を返す場合、これは機能しません。他の誰かがこの問題に直面しましたか?
追加された 著者 Vivek Kothari,

私はJMockitが簡単にそれを完全に切り替えて使用することを発見しました。テストケースを使用してそれを参照してください:

https:// github .com/ko5tik/andject/blob/master/src/test/java/de/pribluda/android/andject/ViewInjectionTest.java

ここで私はAndroidのSKDから来て、完全にアクティビティベースのクラスを嘲笑します スタブ。 JMockitを使うと、最終的なもの、私的なもの、抽象的なもの、その他のものを模倣することができます。

あなたのテストケースでは次のようになります:

public void testFoo(@Mocked final Method targetMethod, 
                    @Mocked  final CacheContext context,
                    @Mocked final  CacheExpire ce) {
    new Expectations() {
       {
          //specify expected sequence of infocations here

           context.getTargetMethod(); returns(method);
       }
    };

   //call your method
    assertSomething(objectUndertest.cacheExpire(context))
3
追加された
JMockitには、連鎖呼び出しのためのアノテーションがあります: @Cascading 。また、このような場合、模擬メソッドの呼び出しを検証する必要がないと仮定して、 Expectations ではなく NonStrictExpectations を使用することをお勧めします。
追加された 著者 Rogério,
あなたの答えを考えていますが、私はどんな方法でもモチートを使用しています。
追加された 著者 jilen,
ありがとう、私はこの注釈を逃した;)私のユニットテストを簡素化
追加された 著者 Konstantin Pribluda,

テストケースを簡単にするための私の提案は、あなたのメソッドをリファクタリングすることです。

メソッドをテストするのに問題が発生したときはいつでも、それはコードの匂いです。なぜテストするのが難しいのですか?また、コードをテストするのが難しい場合は、使用と保守が難しいでしょう。

この場合は、いくつかのレベルの深いメソッドチェーンがあるためです。おそらく、ctx、cacheEnable、およびcacheExpireをパラメータとして渡します。

3
追加された
はい。しかし、これらのフィールドは実行時にAOPコンテキストからのものです。環境を単純化するのは難しいです。
追加された 著者 jilen,
JMockitでこれを行うテクニックがあります。オブジェクトにAOPフィールド注入をシミュレートするフィールドをモックすることができます。または、モックされたインスタンスで証明フィールドを初期化するカプセル化解除技術を使用することもできます
追加された 著者 Konstantin Pribluda,