模拟 COM Interop 接口时出现 MissingMethodException、InvalidOperationException

MissingMethodException, InvalidOperationException when mocking COM Interop interface

我正在尝试对 class 进行单元测试,它依赖于 COM 互操作库的接口。

被测方法:

public void ConfigureAuth(IRequestProcessor5 processor)
{
    processor.AuthPreferences.PutIsReadOnly(false);
    // more configuration statements...
}

我真的很想在这里使用递归模拟,因为我无法控制 COM 代码的形状。我的第一次尝试:

[Fact]
public void ConfigureAuth_SetsReadOnlyToFalse()
{
    var mockProcessor = new Mock<IRequestProcessor5>{DefaultValue = DefaultValue.Mock};
    _testSubject.ConfigureAuth(mockProcessor.Object);
    mockProcessor.Verify(p => p.AuthPreferences.PutIsReadOnly(false));
}

这将引发以下异常(来自测试中的 Verify 调用):

System.InvalidOperationException variable 'p' of type 'QBXMLRP2Lib.RequestProcessor3' referenced from scope '', but it is not defined.

我最初的假设是递归模拟正在工作,但 Verify 表达式中发生了一些奇怪的事情,所以我尝试注释掉 Verify 以测试该假设。然后抛出以下异常(来自被测方法):

System.MissingMethodException Error: Missing method 'instance class QBXMLRP2Lib.IAuthPreferences [MyProject] QBXMLRP2Lib.IRequestProcessor5::get_AuthPreferences()' from class 'Castle.Proxies.IRequestProcessor5Proxy'.

所以递归模拟似乎没有起作用。此外,即使模拟处于 Loose 模式,除非提供 Setup() ,否则 MissingMethodException 也会被抛出。

这是怎么回事,我该如何解决?

要解决此问题,请在解决方案资源管理器中 select 来自单元测试项目的 COM 互操作引用。在属性中,将 Embed Interop Types 更改为 False。 Moq 现在将按 COM 接口的预期行为。

我实际上并不完全理解这里发生了什么。在 Deep Magic(COM Interop)和 Deep Magic(Moq 的表达式和动态代理核心)的交汇处,奇怪和古怪的行为有点正常。不过,我已经确认修复确实有效。