web-dev-qa-db-ja.com

Moq-プロパティ値がセッターを介して設定されていることを確認する方法

このクラスを考えてみましょう:

public class Content
{      
   public virtual bool IsCheckedOut {get; private set;}
   public virtual void CheckOut()
   {
      IsCheckedOut = true;
   }

   public virtual void CheckIn()
   {
      //Do Nothing for now as demonstrating false positive test.
   }
}

Checkinメソッドは意図的に空になっています。これで、いくつかのテストメソッドを使用して、各メソッドの呼び出しのステータスを確認できます。

[TestMethod]
public void CheckOutSetsCheckedOutStatusToTrue()
{
    Content c = new Content();    
    c.CheckOut();
    Assert.AreEqual(true, c.IsCheckedOut); //Test works as expected
}

[TestMethod]
public void CheckInSetsCheckedOutStatusToFalse()
{
    Content c = new Content();
    c.CheckIn();
    Assert.AreEqual(false, c.IsCheckedOut); //Test does not work as expected
}

2番目のテストは、間違った理由で合格しています。では、モック(moq)を使用して、CheckInがIsCheckedOutプロパティを設定していることを確認するにはどうすればよいですか?

ありがとう。

[〜#〜]編集[〜#〜]

明確にするために、IsCheckedOutステータスをfalseに設定するのが仕事であるCheckIn()というメソッドがあります。

上記のテストコードを見ると、プロパティ値をfalseに設定していなくてもTestがfalseを返すことがわかります。これは予想されることですが、ここでは何も問題はありません。

私の質問は特に、CheckIn()メソッドがIsCheckedOutプロパティをfalseに設定したことを確認するにはどうすればよいですか?これを行動検証と呼びます。

一部のコメントは、州の確認に相当することを提案していると思いますか?もしそうなら、私たちが単純に使用できるときにこの部分をモックすることに価値があるとは信じていません:

Content c = new Content();    
c.CheckIn();    
Assert.AreEqual(false, c.IsCheckedOut); //State verification

もちろん私は間違っている可能性がありますので、これらの概念を明確にしてください:)

45
Anton P

以下はうまくいくはずです。モックオブジェクトを次のように構成します。

var mock=new Mock<IContent>();
mock.SetupSet(content => content.IsCheckedOut=It.IsAny<bool>()).Verifiable();

そしてテストコードの後:

mock.VerifySet(content => content.IsCheckedOut=It.IsAny<bool>());

まだテストしていないので、動作するかどうか教えてください。

[〜#〜]編集[〜#〜]。実際、IsCheckedOutのセッターがfalseであるため、これは機能しません。

とにかく、クラスの構築時にIsCheckedOutの値を設定したことがないことがわかりました。以下をContentクラスに追加することをお勧めします。

public Content()
{
    IsCheckedOut=false;
}
47
Konamiman
Mock mockContect = new Mock<Cotent>(); 
mockContent.VerifySet(x => x.IsCheckedOut, Times.Once());

それでうまくいきますか?プライベートセッターがテストを行っていないため、どのようにプレイするかわかりません。しかし、私の公開設定者のために動作します。

これを入手: http://www.codethinked.com/post/2009/03/10/Beginning-Mocking-With-Moq-3-Part-2.aspx

20
Dominic

まずは、チェックアウトするコンテンツを設定してみませんか? CheckIn関数の動作のみをテストしていることに注意してください。

[TestMethod]
public void CheckInSetsCheckedOutStatusToFalse()
{
    // arrange - create a checked out item
    Content c = new Content();
    c.CheckOut();

    // act - check it in
    c.CheckIn();

    // assert - IsCheckedOut should be set back to false
    Assert.AreEqual(false, c.IsCheckedOut);
}
5
Mark Heath

これについて間違った方法で考えている可能性があることをお勧めします。通常、何かを設定し、アクションを実行してから、動作(結果)を確認する必要があります。この場合、セッターによってfalseに設定されなかったことが本当に問題になりますか?特定のシナリオが実行された後、それがfalseであることは重要です。テストを単独で行う場合、これは少し奇妙に思えるかもしれませんが、何であれ、テストはセットで存在します。

2つのクラス間の相互作用をテストする場合は状況が異なります。設定アクションはテストする相互作用であるため、プロパティセッターに期待値を設定しても問題ありません。

Rhino.Mocksを使用しているため、Moqに精通していません。

2
FinnNk

私はあなたに同意します。モックは、クラスの内部メカニズムをテストするのではなく、クラス(テスト中)と他の世界との間の相互作用をテストすることを目的としているため、このシナリオでは価値がありません。

このテストは

Content c = new Content();    
c.CheckIn();    
Assert.AreEqual(false, c.IsCheckedOut); //State verification

あなたが書くことには意味があり、それは偽陽性ではありません!理由が何であれ、CheckInの後の状態がそのようになっていることを確認する必要があります。将来、コンストラクター(または他のメソッド)で状態を設定する場合、このテストによって節約され、CheckInメソッドの実装を強制されます。

CheckInメソッドの実装を忘れないように、初期状態を設定したい場合があります。この場合、2つの方法を使用します(最初の方法は非常に醜いです)。

  1. C.CheckIn();の前にc.CheckOut()を呼び出します。 1つではなく2つのメソッドをテストするので、これは非常に醜いです...しかし、私は数回同じようなことを書いたことを認めます:-)
  2. 私はプライベートセッターを保護し、テスト対象のクラスから継承するテストクラスを作成します。この方法で、c.CheckIn()を呼び出す前にプロパティをtrueに設定して、メソッドが確実に処理を実行できるようにすることができます。

ここにコードがあります:

    public class Content2
{
    public virtual bool IsCheckedOut { get; protected set; }
    public virtual void CheckOut()
    {
        IsCheckedOut = true;
    }

    public virtual void CheckIn()
    {
        //Do Nothing for now as demonstrating false positive test.
    } 
}

    [TestClass]
public class Content2Test : Content2
{
    [TestMethod]
    public void CheckOutSetsCheckedOutStatusToTrue()
    {
        this.CheckOut();
        Assert.AreEqual(true, this.IsCheckedOut); //Test works as expected
    }

    [TestMethod]
    public void CheckInSetsCheckedOutStatusToFalse()
    {
        this.IsCheckedOut = true;
        this.CheckIn();
        Assert.AreEqual(false, this.IsCheckedOut); //Test does not work as expected
    }
}

お役に立てれば幸いです。

0