【问题标题】:Rhino Mocks, void and properties犀牛模拟,虚空和属性
【发布时间】:2009-01-21 23:59:13
【问题描述】:

刚开始使用 Rhino Mocks,我遇到了一个非常简单的问题,我如何模拟一个带有设置属性的 void 的类?

class SomeClass : ISomeClass
{
    private bool _someArg;

    public bool SomeProp { get; set; }

    public SomeClass(bool someArg)
    {
        _someArg = someArg; 
    }

    public void SomeMethod()
    {
        //do some file,wcf, db operation here with _someArg
        SomeProp = true/false;
    }
}

显然这是一个非常人为的例子,谢谢。

【问题讨论】:

    标签: c# tdd mocking rhino-mocks


    【解决方案1】:

    在您的示例中,您不需要 RhinoMocks,因为您显然是在测试被测类的功能。简单的单元测试将代替:

    [Test]
    public void SomeTest()
    {
        var sc = new SomeClass();
            // Instantiate SomeClass as sc object
        sc.SomeMethod();
            // Call SomeMethod in the sc object.
    
        Assert.That(sc.SomeProp, Is.True );
            // Assert that the property is true... 
            // or change to Is.False if that's what you're after...
    }
    

    当你的类依赖于其他类时,测试模拟会更有趣。在您的示例中,您提到:

    //在这里用_someArg做一些文件、wcf、db操作

    即您希望其他一些类设置SomeClass 的属性,这对模拟测试更有意义。示例:

    public class MyClass {
    
        ISomeClass _sc;
    
        public MyClass(ISomeClass sc) {
            _sc = sc;
        }
    
        public MyMethod() {
            sc.SomeProp = true;
        }
    
    }
    

    所需的测试是这样的:

    [Test]
    public void MyMethod_ShouldSetSomeClassPropToTrue()
    {
        MockRepository mocks = new MockRepository();
        ISomeClass someClass = mocks.StrictMock<ISomeClass>();
    
        MyClass classUnderTest = new MyClass(someClass);
    
        someClass.SomeProp = true;
        LastCall.IgnoreArguments();
            // Expect the property be set with true.
    
        mocks.ReplayAll();
    
        classUndertest.MyMethod();
            // Run the method under test.
    
        mocks.VerifyAll();
    }
    

    【讨论】:

    • 在你的最后一个例子中, Lastcall.IgnoreArguments();将是错误的通过,因为您也可以通过传递 someClass.SomeProp = false; 来通过测试
    【解决方案2】:

    取决于您希望模拟对象的保真度。最简单的方法是不用担心,写出一些愚蠢的期望语句。

    [Test]
    public void SomeTest()
    {
       MockRepository mocks = new MockRepository();
       ISomeClass mockSomeClass = mocks.StrictMock<ISomeClass>();
       using(mocks.Record())
       {
          using(mocks.Ordered())
          {
             Expect.Call(MockSomeClass.SomeProp).Return(false);
             Expect.Call(delegate{MockSomeClass.SomeMethod();});
             Expect.Call(MockSomeClass.SomeProp).Return(true);
          }
       }
    }
    

    如果您想要一些更像真实对象的东西,而不需要一组固定的有序响应,您必须在 expect 上使用 do 方法设置委托。

    delegate bool propDelegate();
    delegate void methodDelegate();
    private bool m_MockPropValue = false;
    
    [Test]
    public void SomeTest()
    {
       MockRepository mocks = new MockRepository();
       ISomeClass mockSomeClass = mocks.StrictMock<ISomeClass>();
       using(mocks.Record())
       {
          SetupResult.For(MockSomeClass.SomeProp).Do(new propDelegate(delegate
          {
             return this.m_MockPropValue;
          }));
          Expect.Call(delegate{MockSomeClass.SomeMethod();}).Do(new methodDelegate(delegate
          {
             this.m_MockPropValue = true;
          }));
       }
    }
    

    【讨论】:

    • 我如何断言 SomeMethod 被调用了?
    • 通过使用 Expect.Call(s => s.SomeMethod())
    • 扩展 Slace 的评论,在 using(mocks.Record()) 块之后,您将有一个 using(mocks.Playback()) 块。当您离开播放块时,您在记录块中设置的任何未实现的期望都将导致测试失败。
    【解决方案3】:

    当您使用SetupResult.ForExpect.Call 准备某些东西时,您需要确保它们是虚拟的,否则RhinoMocks 将无法自行实现。

    否则,只需设置结果并按照 Scott Pedersen 所展示的那样进行预期调用

    【讨论】:

      【解决方案4】:

      从问题中并不能完全清楚您要测试的对象是什么 - 如果您只是想检查 SomeClass.SomeMethod() 是否设置了一个属性,那么您不需要模拟,因为您可以做一个简单的基于状态的测试:

      [TestMethod]
      public void SomeMethodTest()
      {
          SomeClass s = new SomeClass();
          s.SomeMethod();
      
          Assert.AreEqual(expectedValue, s.SomeProp);
      }
      

      或者,如果 SomeClass 是某个其他类的依赖项,并且您想测试该类与 SomeClass 之间的交互,那么您可以使用 RhinoMock 在测试的“记录”部分设置方法调用的期望,像这样:

      [TestMethod]
          public void CheckInteractionWithSomeClass()
          {
              MockRepository mocks = new MockRepository();
              ISomeClass someClass = mocks.StrictMock<ISomeClass>();
      
              using (mocks.Record())
              {
                  //record expection that someClass.SomeMethod will be called...
                  someClass.SomeMethod();
              }
      
              using (mocks.Playback())
              {
                  //setup class under test - ISomeClass is injected through the constructor here...
                  ClassUnderTest o = new ClassUnderTest(someClass);
      
                  o.MethodOnClassUnderTestThatShouldCallSomeClass.SomeMethod();
      
                  //any other assertions...
              }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-02-15
        • 1970-01-01
        • 2010-11-07
        • 2010-10-29
        • 2016-06-06
        • 1970-01-01
        • 2011-11-12
        • 2010-11-10
        相关资源
        最近更新 更多