使用Moq模拟Delegate.Invoke()会在LINQ中抛出InvalidCast异常

时间:2014-01-23 01:28:02

标签: c# linq unit-testing delegates moq

假设我有IService界面:

public interface IService
{
    string Name { get; set; }
}

返回此接口的委托Func<IService>

在我的单元测试中,我想使用Moq模拟委托的Invoke()方法,如下所示:

[TestMethod]
public void UnitTest()
{
    var mockService = new Mock<IService>();

    var mockDelegate = new Mock<Func<IService>>();
    mockDelegate.Setup(x => x.Invoke()).Returns(mockService.Object);

    // The rest of the test
}

不幸的是mockDelegate.Setup(...)会引发System.InvalidCastException

  

测试方法   UnitTest引发了异常:

     

System.InvalidCastException:无法转换类型的对象“System.Linq.Expressions.InstanceMethodCallExpressionN”来   输入'System.Linq.Expressions.InvocationExpression'。

     

在Moq.ExpressionExtensions.GetCallInfo(LambdaExpression表达式,模拟模拟)

     

在Moq.Mock&LT;&GT; C_ DisplayClass1c`2.b _1b()

     

在Moq.PexProtector.Invoke(Func`1函数)

     

在Moq.Mock.Setup(模拟1 mock, Expression 1表达式,条件条件)

     

在Moq.Mock 1.Setup(Expression 1表达式)

     

在UnitTests.cs中的UnitTest():第38行

第38行是mockDelegate.Setup(x => x.Invoke()).Returns(mockService.Object);

我错过了什么吗?或者模拟委托调用通常不是一个好主意?

谢谢。

2 个答案:

答案 0 :(得分:36)

在Moq中这是100%可能的,这是如何:

var mockService = new Mock<IService>();

var mockDelegate = new Mock<Func<IService>>();
mockDelegate.Setup(x => x()).Returns(mockService.Object);

您获得InvalidCastException的原因是因为您正在创建委托类型的Mock<T>。因此,期望Expression的类型为InvocationExpressionx()),而不是InstanceMethodCallExpressionNx.Invoke())。

这也允许您验证Mock代表的调用,例如

mockDelegate.Verify(x => x(), Times.Once);

我已将此作为答案发布,因为虽然对于这种情况可能没有必要,但知道它肯定是有用的。

答案 1 :(得分:1)

此答案是SLaksnemesv条评论的摘要。

首先没有理由嘲笑Func<IService> delegate。相反,人们可以写:

[TestMethod]
public void UnitTest()
{
    var mockService = new Mock<IService>();

    Func<IService> mockDelegate = () => mockService.Object;

    // The rest of the test
}

存在异常,因为Moq不支持此方案。但是,不要抛出NotSupportException而不是那么好InvalidCastException