单元测试Linq中的虚拟方法

时间:2010-09-16 18:31:10

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

我有以下类结构,我需要进行单元测试:

public interface IFoo
{
    int Value { get;}
    int GetValue();
}

public class BaseClass : IFoo
{
    public virtual int Value { get { return 100; } }
    public virtual int GetValue()
    {
        return Value;
    }
}

public class ChildClass : BaseClass, IFoo
{
    public override int GetValue()
    {
        return Value;
    }
}

我正在尝试使用RhinoMocks测试ChildClass.GetValue()方法。

我有以下存根代码:

public ChildClass CreateChildClass(int value)
{
   var childClass = MockRepository.GenerateStub<ChildClass>();
   childClass.Stub(x => x.Value).Return(value);
   return childClass;            
}

以下UnitTest代码:

public IEnumerable<IFoo> CreateList()
{
   yield return CreateChildClass(1000);
   yield return CreateChildClass(2000);
}

[TestMethod]
public void virtualMethodTest()
{
   var list = CreateList();
   var query = from p in list
               select p.GetValue(); //I can't use p.Value

   var sum = query.Sum(p => p);
 }

手头的问题是总和总是为零。我可以快速查看列表,并使用CreateList()中的正确值查看两个模拟对象。

是否可以对子类进行单元测试虚拟方法?或者我需要使用不同的RhinoMocks方法吗?

由于

1 个答案:

答案 0 :(得分:2)

两件事:

  • 您正在创建具体类的存根,而不是IFoo。模拟在其内部工作中具有高度反射性,因此多态调用可能会也可能不会表现相同,具体取决于框架和调用的确切性质。
  • 您正在创建存根,这些存根本质上会忽略对其接口所做的任何调用(返回返回类型的默认值)。这是你问题的直接原因;不期望GetValue(),因此它返回默认的整数值(0)。

您希望测试实际类的某些行为,但要覆盖某些其他行为(副作用,不是测试范围的一部分,等等)。 RhinoMocks的基本答案是PartialMock,它将默认为实际类的行为,除非您希望进行某个调用。因此,代替GenerateStub&lt;&gt;(),创建MockRepository的实例并实例化新的MockRepository.PartialMock()。期望您要覆盖的内部行为,但不要触及其他任何内容。您可能必须使用较旧的录制和播放方法;我实际使用的RhinoMocks版本在实例化PartialMock然后在实例上调用Expect()时行为不正确。

改变将是:

//instantiate Mocks in class scope, as an instance of MockRepository

public ChildClass CreateChildClass(int value)
{
   var childClass = Mocks.PartialMock<ChildClass>();
   childClass.Expect(x => x.Value).Return(value);
   return childClass;            
}