【问题标题】:Mocking, virtual and more模拟、虚拟等
【发布时间】:2011-09-19 11:13:32
【问题描述】:

这个问题可能会被多次问到 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 中处理这种情况?如果我将属性 Foo 设为虚拟,它可以正常工作。但是,我不想那样做。

【问题讨论】:

  • 这是意料之中的,错误说明了原因:make sure that you are calling a virtual (C#) - 所以尝试将 Foo 设为虚拟!
  • Carsten- 我正在为我的代码寻求替代方案或更好的设计。我已经提到过 - _ 如果我将属性 Foo 设为虚拟,它可以正常工作。但是,我不想那样做。_
  • 您想要一个更好的可测试/可模拟设计 - 轻松将方法提取到接口中并模拟这些......

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


【解决方案1】:

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

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

【讨论】:

  • Expect.Call(myObjB.Foo).Return(true);. 如果我将属性 Foo 设为虚拟,它可以正常工作。但是,我不想那样做。
  • @SeeSharp,模拟只能通过替换虚拟/抽象/接口方法来工作。他们需要记录通话,以便您可以编写像Expect.Call 这样的断言。
【解决方案2】:

如果一个属性需要被模拟,并且它的原始行为不能被模拟掉,这里有一个替代方案。您将代码从 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);

【讨论】:

  • 但是,只是为了模拟,在生产代码中注入这样的东西并不是很受欢迎。
  • @SeeSharp:如果您不愿意为了更好的测试覆盖率而做出这种牺牲,您可能需要考虑一种新的策略来测试此代码(否则它将未经测试) .实际上,我建议从B 中提取一个接口,然后对其进行模拟。然后独立测试B.Foo
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多