2

刚从 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;
    }
}

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

4

4 回答 4

6

在您的示例中,您将不需要 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();
}
于 2009-01-22T12:17:40.377 回答
3

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

[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;
      }));
   }
}
于 2009-01-22T00:30:39.617 回答
0

当你准备东西时,SetupResult.ForExpect.Call需要确保它们是virtual,否则 RhinoMocks 将无法进行自己的实现。

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

于 2009-01-22T00:34:12.870 回答
0

从这个问题中您要测试的对象是什么并不完全清楚 - 如果您只是想检查 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...
        }
    }
于 2009-01-22T11:43:18.760 回答