34

わかりました。Rhino Mocks の新しい AAA 構文について多くの混乱があったことは承知していますが、正直に言うと、これまで見てきたことから、私は気に入っています。読みやすくなり、キーストロークを節約できます。

基本的に、私は基本ListController的にいくつかのリストを担当する a をテストしています:)最終的にDALになるインターフェースを作成しましたが、これはもちろん今のところスタブ化されています.

次のコードがありました。

(managerはテスト対象のシステム、dataはスタブ化されたデータ インターフェイス)

    [Fact]
    public void list_count_queries_data()
    {
        data.Expect(x => x.ListCount(1));
        manager.ListCount();
        data.VerifyAllExpectations();
    }

このテストの主な目的は、マネージャーが実際に DAL をクエリしていることを確認することです。DAL は実際には存在しないため、「実際の」値は返されないことに注意してください。

ただし、次のような戻り値を持つように期待を変更する必要があるため、これは失敗しています。

        data.Expect(x => x.ListCount(1)).Return(1);

その後、これは正常に実行され、テストはパスしますが、この時点で私を混乱させているのは、戻り値が何も意味しないことです。100、50、42 などに変更でき、テストは常にパスしますか?

テストは明示的である必要があり、期待される条件が正しく満たされていない場合は完全に失敗する必要があるため、これは私を緊張させますか?

テストを次のように変更すると (「1」は、カウントがリンクされていると予想される ID です):

    [Fact]
    public void list_count_queries_data()
    {
        manager.ListCount();
        data.AssertWasCalled(x => x.ListCount(1));
    }

それはすべて問題なく合格し、頭のテストを に切り替えると、AssertWasNotCalled期待どおりに失敗します..また、読みやすく、テスト対象がより明確になり、最も重要なことに、期待どおりに合格および不合格になると思います!

では、最初のコード例で何か不足していますか? スタブでアサーションを作成することについてどう思いますか? (ここで興味深い議論がありました。私は個人的にこの反応が好きでした。

4

3 に答える 3

53

あなたのテストは何を達成しようとしていますか?

どのような動作または状態を確認していますか? 具体的には、共同作業者 (データ) がそのメソッドを呼び出していることを確認していますか (相互作用ベースのテスト)、または他の場所で結果を確認しながら、テスト対象のクラスを駆動するために既定の値を返すListCountようにしたいだけですか (従来の状態ベースのテスト)。 ListCount?

期待値を設定したい場合は、モックと期待値を使用MockRepository.CreateMock<IMyInterface>()してください:myMock.Expect(x => x.ListCount())

メソッドをスタブ化する場合は、 and を使用MockRepository.CreateStub<IMyInterface>()myStub.Stub(x => x.ListCount())ます。

(余談: stub.AssertWasCalled() を使用して、mock.Expect とほぼ同じことを達成し、おそらくより優れた構文を読み取ることができることはわかっていますが、モックとスタブの違いを掘り下げているだけです)。

Roy Osherove は、モックとスタブについて非常に優れた説明をしています。

もっとコードを投稿してください!

スタブ (またはモック) を作成する方法と、テスト対象のクラスに関して結果がどのように使用されるかの全体像が必要です。ListCount入力パラメータはありますか? もしそうなら、それは何を表していますか?特定の値で呼び出されたかどうか気にしますか? が特定の値をListCount 返すかどうか気にしますか?

Simon Laroche が指摘したように、Manager が ListCount のモック/スタブ化された戻り値で実際に何もしていない場合、それが原因でテストは成功または失敗しません。テストが期待するのは、モック/スタブ化されたメソッドが呼び出されることだけです。それ以上のことはありません。

問題をよりよく理解するために、次の 3 つの情報を検討してください。

  1. テスト対象
  2. どんな状況で?
  3. 期待される結果は何ですか?

比較: モックを使用した対話ベースのテスト。モックの呼び出しがテストです。

[Test]
public void calling_ListCount_calls_ListCount_on_DAL()
{
   // Arrange
   var dalMock = MockRepository.Mock<IDAL>();
   var dalMock.Expect(x => x.ListCount()).Returns(1);
   var manager = new Manager(dalMock);

   // Act
   manager.ListCount();

   // Assert -- Test is 100% interaction based
   dalMock.VerifyAllExpectations();   
}

スタブを使用した状態ベースのテスト。スタブはテストを駆動しますが、期待の一部ではありません。

[Test]
public void calling_ListCount_returns_same_count_as_DAL()
{
   // Arrange
   var dalStub = MockRepository.Stub<IDAL>();
   var dalStub.Stub(x => x.ListCount()).Returns(1);
   var manager = new Manager(dalMock);

   // Act
   int listCount = manager.ListCount();

   // Assert -- Test is 100% state based
   Assert.That(listCount, Is.EqualTo(1),
       "count should've been identical to the one returned by the dal!");
}

個人的には可能な限り状態ベースのテストを好みますが、対話ベースのテストは、Tell, Don't Askを念頭に置いて設計された API で必要になることがよくあります。

API の混乱。モックはスタブではありません。それとも彼らですか?

rhino モックのモックとスタブの区別は混乱しています。伝統的に、スタブは期待値を持つことを意図していません。そのため、テスト double にメソッドが呼び出されていなくても、これが直接テストの失敗の原因になることはありません。

... ただし、Rhino Mocks API は強力ですが、受け入れられている用語に反するスタブに期待を設定できるため、混乱を招きます。用語についてもあまり考えていません。私の意見では、区別がなくなり、テストで呼び出されるメソッドが役割を二重に設定した方がよいでしょう。

于 2010-01-15T23:17:48.757 に答える
1

manager.ListCount() が戻り値で何をしているのかに関係していると思います。

それを使用していない場合、DAL は問題にならないものを返すことができます。

public class Manager
{
    public Manager(DAL data)
    { 
        this.data = data
    }
    public void ListCount()
    {
        data.ListCount(1); //Not doing anything with return value
        DoingSomeOtherStuff();
    }    
}

リストカウントがその値で何かをしている場合は、それが何をしているかについてアサーションを設定する必要があります。例えば

Assert.IsTrue(manager.SomeState == "someValue");
于 2009-01-29T17:36:29.420 に答える
0

使ってみましたか

data.AssertWasCalled(x => x.ListCount(1) = Arg.Is(EXPECTED_VALUE));
于 2010-01-15T22:23:32.300 に答える