14

少し前に、 MartinFowlerによるMocksAre n't Stubsの記事を読みましたが、複雑さの追加に関して外部の依存関係が少し怖いことを認めなければならないので、質問したいと思います。

単体テストで使用するのに最適な方法は何ですか?

テスト対象のメソッドの依存関係を自動的にモックするために、常にモックフレームワークを使用する方がよいでしょうか、それとも、たとえばテストスタブなどのより単純なメカニズムを使用する方がよいでしょうか。

4

6 に答える 6

12

マントラが進むにつれ、「おそらく機能する可能性のある最も単純なものを使用してください」。

  1. 偽のクラスが仕事を成し遂げることができるなら、彼らと一緒に行きなさい。
  2. 複数のメソッドをモックするインターフェースが必要な場合は、モックフレームワークを使用してください。

モックはテストをもろくするので、常にモックを使用することは避けてください。モックされたインターフェースまたは実装が変更された場合、テストは実装によって呼び出されるメソッドに関する複雑な知識を持っています...テストは失敗します。これは悪いことです。SUTを実行するだけでなく、テストを実行するために追加の時間を費やすことになります。テストは、実装と不適切に親密であってはなりません。
だからあなたの最善の判断を使ってください..それが私が書くのを節約するのを助けるとき、私はモックを好みます-n>>3メソッドで偽のクラスを更新します。

エピローグ/審議の更新
:(モキストテストの例としてToranBillupsに感謝します。以下を参照してください)
こんにちはダグ、まあ、私たちは別の聖なる戦争に超越したと思います-クラシックTDDers対モキストTDDers。私は前者に所属していると思います。

  • test#101 Test_ExportProductListを使用していて、IProductService.GetProducts()に新しいパラメーターを追加する必要があることがわかった場合。私はそれを行い、このテストをグリーンにします。リファクタリングツールを使用して、他のすべての参照を更新します。今、私はこのメンバーを呼んでいるすべてのモキストテストが爆発しているのを見つけました。次に、戻ってこれらすべてのテストを更新する必要があります-時間の無駄です。shouldPopulateProductsListOnViewLoadWhenPostBackIsFalseが失敗したのはなぜですか?コードが壊れているからですか?むしろ、テストは壊れています。私は1つのテストの失敗=1つの場所を修正することを好みます。嘲笑の頻度はそれに反します。スタブはもっと良いでしょうか?もし私がfake_class.GetProducts()..を持っていたら、複数のExpect呼び出しでショットガン手術の代わりに1つの場所を変更する必要があります。結局のところ、それはスタイルの問題です..一般的なユーティリティメソッドMockHelper.SetupExpectForGetProducts()があれば、それでも十分です..しかし、これは珍しいことがわかります。
  • テスト名に白い帯を付けると、テストが読みづらくなります。モックフレームワークの多くの配管コードは、実行されている実際のテストを隠します。
  • モックフレームワークのこの特定のフレーバーを学ぶ必要があります
于 2008-09-06T20:00:23.650 に答える
8

私は通常、期待のためにモックを使用することを好みます。値を返すスタブでメソッドを呼び出すと、通常は値が返されるだけです。しかし、モックでメソッドを呼び出すと、値が返されるだけでなく、メソッドが最初に呼び出されたという設定も強制されます。つまり、期待値を設定してからそのメソッドを呼び出さないと、例外がスローされます。期待値を設定するということは、本質的に「このメソッドが呼び出されない場合は、何か問題が発生した」ということです。逆に言えば、モックでメソッドを呼び出して期待値を設定しなかった場合、例外がスローされ、基本的に「期待していなかったときにこのメソッドを呼び出して何をしているのですか」というメッセージが表示されます。

呼び出しているすべてのメソッドに期待を持たせたくない場合があるため、一部のモッキング フレームワークでは、設定した期待のみが適用され、他のすべてのメソッド呼び出しが処理されるという点で、モック/スタブ ハイブリッドのような「部分的な」モックを許可します。値を返すだけという点でスタブに似ています。

ただし、スタブを使用する有効な場所の 1 つは、レガシ コードにテストを導入する場合です。場合によっては、すべてをリファクタリングしてモックを簡単に、または可能にするよりも、テストしているクラスをサブクラス化してスタブを作成する方が簡単な場合があります。

そしてこれに…

モックはテストを脆弱にするため、常に使用しないでください。モック化されたインターフェイスが変更された場合、テストは実装によって呼び出されるメソッドの複雑な知識を持つようになりました... テストが壊れます。だからあなたの最善の判断を下してください.. <

...インターフェイスが変更された場合、テストは中断したほうがよいと思います。単体テストの要点は、現在存在するコードを正確にテストすることだからです。

于 2008-09-07T00:16:48.747 に答える
2

それは、実行しているテストの種類によって異なります。動作ベースのテストを行っている場合は、依存関係との相互作用が発生することを確認できるように、動的モックが必要になる場合があります。ただし、状態ベースのテストを行っている場合は、値などを確認するためにスタブが必要になる場合があります

たとえば、以下のテストでは、プロパティ値が設定されていることを確認できるようにビューをスタブ化しています (状態ベースのテスト)。次に、サービス クラスの動的モックを作成して、テスト (相互作用/動作ベースのテスト) 中に特定のメソッドが確実に呼び出されるようにします。

<TestMethod()> _
Public Sub Should_Populate_Products_List_OnViewLoad_When_PostBack_Is_False()
    mMockery = New MockRepository()
    mView = DirectCast(mMockery.Stub(Of IProductView)(), IProductView)
    mProductService = DirectCast(mMockery.DynamicMock(Of IProductService)(), IProductService)
    mPresenter = New ProductPresenter(mView, mProductService)
    Dim ProductList As New List(Of Product)()
    ProductList.Add(New Product())
    Using mMockery.Record()
        SetupResult.For(mView.PageIsPostBack).Return(False)
        Expect.Call(mProductService.GetProducts()).Return(ProductList).Repeat.Once()
    End Using
    Using mMockery.Playback()
        mPresenter.OnViewLoad()
    End Using
    'Verify that we hit the service dependency during the method when postback is false
    Assert.AreEqual(1, mView.Products.Count)
    mMockery.VerifyAll()
End Sub
于 2008-09-06T20:05:42.623 に答える
2

組み合わせて使用​​するのが最善であり、独自の判断を使用する必要があります。私が使用するガイドラインは次のとおりです。

  • 外部コードの呼び出しがコードの予期される (外向きの) 動作の一部である場合は、これをテストする必要があります。モックを使用します。
  • 呼び出しが実際に外部の世界が気にしない実装の詳細である場合は、スタブを優先します。でも:
  • テストされたコードの後の実装が誤ってスタブを迂回するのではないかと心配し、それが発生したかどうかを確認したい場合は、モックを使用してください。テストをコードに結合していますが、これは、スタブでは不十分であり、テストをやり直す必要があることに気付くためです。

2 番目のモックは、一種の必要悪です。ここで実際に起こっていることは、スタブを使用するかモックを使用するかに関係なく、場合によっては必要以上にコードに結合する必要があるということです。そのような場合は、スタブよりもモックを使用することをお勧めします。これは、その結合がいつ壊れて、コードがテストで想定したとおりに記述されなくなったかがわかるためです。これを行うときは、テストにコメントを残しておくのがおそらく最善です。

繰り返しますが、これはコードの匂いであり、最後の手段です。これを頻繁に行う必要がある場合は、テストの書き方を考え直してみてください。

于 2008-09-06T20:12:31.703 に答える
2

Statist と Interaction は気にしないでください。役割と関係について考えてみましょう。オブジェクトが隣人と協力して仕事を完了する場合、その関係 (インターフェースで表現されている) は、モックを使用したテストの候補です。オブジェクトが少し動作する単純な値オブジェクトである場合は、直接テストしてください。モック (またはスタブ) を手で書く意味がわかりません。それが私たち全員がそれから始めてリファクタリングした方法です。

より長い議論については、http://www.mockobjects.com/bookをご覧ください。

于 2009-05-21T18:33:07.163 に答える
1

このブログ投稿で、まさにこの質問に関するLukeKaniesの議論を読んでください。彼はJayFieldsからの投稿を参照しており、テストをより堅牢にするために[ruby's/mocha'sと同等の]stub_everythingを使用する方が好ましいとさえ示唆しています。Fieldsの最後の言葉を引用すると、「Mochaを使用すると、スタブを定義するのと同じくらい簡単にモックを定義できますが、必ずしもモックを好む必要があるわけではありません。実際、私は通常、スタブを好み、必要に応じてモックを使用します。 「」

于 2008-09-06T19:37:24.940 に答える