【问题标题】:Mocking and Marshal.ReleaseComObject()模拟和 Marshal.ReleaseComObject()
【发布时间】:2014-02-12 12:07:18
【问题描述】:

我在设置模拟时遇到问题,所以我可以在我的模拟对象上调用 Marshal.ReleaseComObject()

我正在使用 Moq 设置 IFeature 类型的模拟(来自第三方接口库)。模拟设置相当简单:

  var featureMock = new Mock<IFeature>(); 
  IFeature feature = featureMock.Object; 

在我的代码中,功能对象是在一个 while 循环中创建的,通过一种游标 (FeatureCursor) 运行。由于第三方库的遗留问题,Feature 对象存在内存泄漏问题。因此,我必须通过Marshal.ReleaseComObject() 释放对象,如代码所示;

public class XXX
{

      public void DoThis()
      {
        IFeatureCursor featureCursor; 
        //...fill the cursor with features; 

        IFeature feature = null; 
        while ((feature = featureCursor.NextFeature)!= null)
        {
           //Do my stuff with the feature
          Marshal.ReleaseComObject(feature); 
        }

      }

}

当我使用真正的特征光标和特征时它可以工作,但是当我在单元测试中模拟该特征时,我得到一个错误:

"System.ArgumentException : The object's type must be __ComObject or derived from __ComObject."

但是如何将它应用到我的 Mock 对象?

【问题讨论】:

    标签: c# unit-testing mocking moq


    【解决方案1】:

    Mocked IFeature 将只是一个标准的 .NET 类,而不是 COM 对象,这就是您的测试当前抛出 The object's type must be __ComObject... 异常的原因。

    你只需要把对Marshal.ReleaseComObject(feature);的调用封装起来,先检查对象是否是COM对象:

    if (Marshal.IsComObject(feature)
    {
        Marshal.ReleaseComObject(feature);
    }
    

    那么您的测试将通过但不会调用Marshal.ReleaseComObject(生产代码会调用它)。

    因为听起来您实际上想以某种方式验证 Marshal.ReleaseComObject 是否被代码调用,您需要做更多的工作。

    因为它是一个静态方法并且实际上并没有对对象本身做任何事情,所以你唯一的选择就是创建一个包装器:

    public interface IMarshal
    {
        void ReleaseComObject(object obj);
    }
    
    public class MarshalWrapper : IMarshal
    {
        public void ReleaseComObject(object obj)
        {
            if (Marshal.IsComObject(obj))
            {
                Marshal.ReleaseComObject(obj);
            }
        }
    }
    

    然后让您的代码依赖于IMarshal,您也可以在测试和验证中模拟它:

    public void FeaturesAreReleasedCorrectly()
    {
        var mockFeature = new Mock<IFeature>();
        var mockMarshal = new Mock<IMarshal>();
    
        // code which calls IFeature and IMarshal
        var thing = new Thing(mockFeature.Object, mockMarshal.Object);
        thing.DoThis();
    
        // Verify that the correct number of features were released
        mockMarshal.Verify(x => x.ReleaseComObject(It.IsAny<IFeature>()), Times.Exactly(5));
    }
    

    【讨论】:

    • 漂亮!!非常感谢。为什么我没有考虑制作 MarshalWrapper。我将几乎所有其他内容都包含在我的代码中:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-09
    • 2023-04-02
    • 1970-01-01
    相关资源
    最近更新 更多