模拟,虚拟等等

时间:2011-09-19 11:13:33

标签: c# unit-testing mocking rhino-mocks

对于 RhinoMocks ,这个问题会多次被问到,但我会尝试提出一些不同的看法。我有这样的情况 -

class A
{
   X parentOfB;
   A()
   { 
       X parentOfB = someObj;
       if(<something>)
       {
         B objB = parentOfB as B  // NOTE THIS 
         if(objB.Foo)            // call the property here
         {
            // some code ....
         }
       }
   }
}

class B : X
{
   // gets initialised to true somewhere in the program. Don't bother much
   protected bool status ;
   B() {}

   // Property
   public bool Foo
   {
     return status;
   }

}

惩戒: 现在,我想做这样的事情 -

var mock = new MockRepository();

var myObjB = mock.StrictMock<B>();

// call Db class to populate the objB object and then set the expectation as 
// below  
// ...
// ...
Expect.Call(myObjB.Foo).Return(true);
mock.ReplayAll();
var objA = new A();
mock.VerifyAll();

错误: 呼叫无效,最后一次呼叫已被使用或未进行任何呼叫(确保您正在调用虚拟(C#)/可覆盖(VB)方法)。

问题是,在A的ctor中访问具体的类B以访问该属性。如何在 RhinoMocks 中处理这种情况?如果我将prooerty Foo视为虚拟,它可以正常工作。但是,我不想这样做。

2 个答案:

答案 0 :(得分:3)

首先,检查您的异常堆栈跟踪,并查看“无效调用”错误的来源。它来自Expect.Call行吗?如果是这样,请从图片中删除A类。

其次,所有模拟框架都需要一种方法来检查是否已调用属性/方法。它们用一些记录调用发生方式的代码替换常规属性/方法代码。为了替换代码,模拟的属性或方法必须是虚拟的或抽象的,或者应该为接口创建模拟。

答案 1 :(得分:0)

如果某个属性需要被嘲笑,并且其原始行为无法被嘲笑,那么这里有一个替代方案。您将代码从B.Foo移动到新属性中,并为B.Foo创建虚拟虚拟替换。

class B
{
    // Old code here
    public bool RealFoo { get { return status; } }

    // New dummy code
    public virtual bool Foo { get { return RealFoo; } }
}

然后从您的模拟代码中,您可以记录调用Foo的时间,并且您也可以调用“真实”代码:

var myObjB = mock.StrictMock<B>();

Expect.Call(myObjB.Foo).Return(myObjB.RealFoo);