Moq无法在构造函数中使用可为null的参数创建类的模拟对象

时间:2011-06-16 20:32:03

标签: c# unit-testing mocking moq nullable

我有这堂课:

public class TestClass
{
 public TestClass(int? foo, string bar)
 {
   //..Something
 }
}

我试图用这样的MOQ模拟它

var mockA = new Mock<A>(new object[] {(int?)1, string.Empty})

或者,

var mockA = new Mock<A>(new object[] {1 as int?, string.Empty})

即便如此

var mockA = new Mock<A>(new object[] {(int?)null, string.Empty})

当我试图获得这样的对象时

var objA = mockA.Object

它抛出此异常

无法实例化类的代理:TestClass。 找不到与给定参数匹配的构造函数: System.Int32, System.String

(对于第三个,它抛出空引用异常)

如何让它识别出第一个参数的类型为Nullable System.Int32而不是System.Int32。

(请忽略我正在嘲笑一个类而不是一个接口。)

2 个答案:

答案 0 :(得分:8)

为了使用Moq模拟对象,对象本身必须有一个public空构造函数。 您想要模拟的方法必须为virtual才能被覆盖。

修改

我正在运行Moq v4.0.20926(最新的NuGet)以及以下工作:

[TestMethod]
public void TestMethod1()
{
    var mock = new Mock<TestClass>(new object[] {null, null});
    mock.Setup(m => m.MockThis()).Returns("foo");

    Assert.AreEqual("foo", mock.Object.MockThis());
}

public class TestClass
{
    public TestClass(int? foo, string bar)
    {
    }

    public virtual string MockThis()
    {
        return "bar";
    }
}

答案 1 :(得分:4)

这样做的原因是装箱一个可以为空的值并没有真正包装Nullable<T>值,它会将值放在里面。

基本上:

  1. 如果您输入具有值的可空值,则会获得该值的盒装版本,因此(int?)1的盒装版本与{1的盒装版本相同1}}
  2. 如果您输入具有值的可空值,则会获得无引用的空引用
  3. 您可以将拳击操作视为与此类似:

    public static object Box(int? value)
    {
        if (value.HasValue)
            return value.Value; // boxes the int value
    
        return null;            // has no type
    }
    

    换句话说,您的object[]数组根本没有得到可空值的副本,它只获取int值的副本或null - 引用,两者都不带Nullable<T>类型。

    以下是一些要测试的LINQPad代码:

    void Main()
    {
        int? i = 1;
        object o = i;
    
        o.Dump();
        o.GetType().Dump();
    
        i = null;
        o = i;
        o.Dump();
        o.GetType().Dump();
    }
    

    输出:

      

    1
      System.Int32
      
      [的NullReferenceException]