2013-07-29 6 views
5

FakeItEasyを使用して、オブジェクトのメソッドがこの同じオブジェクトの別のメソッドを呼び出すかどうかを確認するにはどうすればよいですか?同じオブジェクトの別のメソッドにFakeItEasyのA.CallTo()を使用

テスト:

[TestMethod] 
public void EatBanana_CallsWillEat() 
{ 
    var banana = new Banana(); 
    var myMonkey = new Monkey(); 

    myMonkey.EatBanana(banana); 

    //this throws an ArgumentException, because myMonkey is a real instance, not a fake 
    A.CallTo(() => myMonkey.WillEat(banana) 
    .MustHaveHappened(); 
} 

クラス:

public class MyMonkey { 
    private readonly IMonkeyRepo _monkeyRepo; 

    public MyMonkey(IMonkeyRepo monkeyRepo) { 
    _monkeyRepo = monkeyRepo; 
    } 

    public void EatBanana(Banana banana) { 
    //make sure the monkey will eat the banana 
    if (!this.WillEat(banana)) { 
     return; 
    } 

    //do things here 
    } 

    public bool WillEat(Banana banana) { 
    return !banana.IsRotten; 
    } 
} 

私は提案を開いています。私が間違ったことをしているなら、私に知らせてください。

+2

私はそれを理解しているので、これは実際にFIEのためではありません。 FIEは擬似オブジェクトを提供し、プロダクションコードをより簡単に突き刺すことができます。あなたが指摘しているように、あなたは偽物を持っていません。 私の経験では、この種のテストは通常​​良い考えではありません。あなたのMyMonkeyクラスは、かなり自己完結型のユニットでなければなりません。バナナを食べるように指示されたときは、それ自身のメソッドを呼び出すかどうかを心配するのではなく、全体的な動作をテストする方が良いでしょう。たとえば、「ここでは何をしているのか」ということから、何が起こったかの手がかりに基づいてバナナが食べられたかどうかを知ることができますか? –

+0

@BlairConrad私の本当のシナリオでは、WillEatはもっと複雑で、独自のテストをしています。これはEatBananaが持つテストの一つに過ぎません。このテストでは、EatBananaに実際のWillEatを呼び込ませても、1回のテストで2つの機能をテストすることはできませんか?それから、WillEatが変更された場合、それは悪いニュースである、そのテストを破る可能性があります。 –

+4

私はあなたのポイントを見ます。それはトリッキーです。 'WillEat'が別のオブジェクトに住んでいた場合、私たちはそのオブジェクトの偽造を促し、' MyMonkey'に注入します(痛い)。私が本当に言うことができるのは、クライアントの観察可能な結果に依拠して、外部からの「MyMonkey」のテストを試みることが、デフォルトの最善の位置にあると思うということです。 しかし、あなたはその中に考えを入れて、あなたの痛みを軽減し、テストの数を減らし、与えられた数に対して壊れる数を減らす解決策を見つけました。あなたが最良のコードを知っているので、それがあなたのために働くのであれば... 私はちょうどあなたが代替手段を知って欲しかった。 –

答えて

2

これは可能です。 WillEatのメソッドが仮想だった場合 - それ以外の場合はFakeItEasyはそれを偽造できません。その変更に伴い

、あなたはこれを行うことができます:

[TestMethod] 
public void EatBanana_CallsWillEat() 
{ 
    var fakeMonkey = A.Fake<MyMonkey>(); 

    fakeMonkey.EatBanana(new Banana()); 

    A.CallTo(()=>fakeMonkey.WillEat(A<Banana>._)).MustHaveHappened(); 
} 

私はまだ(私はコメントでrantedとして)それは良いアイデアだと確信していない - 私はあなたが他に頼るほうが良いと思います私はあなたのシステムに精通していません。これが最善の方法だと思われる場合は、サンプルコードが役立ちます。

3

なぜあなたはテストされたオブジェクトを嘲笑していますか?何を正確にあなたがテストしようとしていますか? WillEatに電話するという確認はほとんど価値がありません。どの情報を消費者に提供していますか?結局のところ、消費者はメソッドがどのように実装されているか気にしません。消費者の気になるものはの結果です。

サルがバナナを食べるとどうなりますかは腐っていません?あなたが適切に偽造し、ここで注入されIMonkeyRepoに検証のすべての並べ替えを行うことができます

[TestMethod] 
public void EatBanana_CAUSES_WHAT_WhenBananaIsNotRotten() 
{ 
    var repo = A.Fake<IMonkeyRepo>(); 
    var monkey = new Monkey(repo); 
    var freshBanana = new Banana { IsRotten = false }; 

    monkey.EatBanana(freshBanana); 

    // verifications here depend on what you expect from 
    // monkey eating fresh banana 
} 

注:あなたのテストでは、この質問に答える必要があります。

+0

良い点。私がWillEatを模倣しないで、EatBananaが本当のWillEatを呼び出せるようにするなら、私は1つのテストで2つの機能をテストしていますか?この例では、WillEatは自明ですが、私の実際の状況では、より複雑で、引数に基づいて派生したオブジェクトを返します。したがって、私は嘲笑して呼び出されたことを確認することが正しい方法でしょう。私は現在、WillEatのテストとEatBananaのテストを別に行っています。これには、レポが呼ばれたことも含まれています。たぶん私はきめ細かくなっていますか? –

+3

@ JoshNoe:それほど細かいことはありません。 'WillEat'がその複合体ならば、おそらくそれは自分のクラスに生きるべきですか?おそらく、この機能を* food-evaluator-sort-of-thing *に抽出して、それを猿に注入する方が理にかなっていますか?テストは*シンプルでなければなりません - もしそうでなければ*通常*デザインを再訪する良い指標です。ちなみに、 'Monkey'は' IMonkeyRepository'に依存するのはなぜですか? –

関連する問題