通过 RequestComAddInAutomationService 在 C# .NET 中进行 VSTO 单元测试 Office 加载项

VSTO Unit Testing Office AddIn in C# .NET via RequestComAddInAutomationService

在过去的几周里,我研究并阅读了各种 Whosebug 问题以及其他教程和文档(N.B。其中一些在下面),试图找到一种对 VSTO 插件进行单元测试的方法。

不幸的是,它总是在我的测试中导致 E_NOINTERFACE 异常。

我正在使用的代码如下 - ThisAddin 部分 class 的一个摘录覆盖了 RequestComAddinAutomationService,另一个描述了测试实用程序接口、测试本身,以及一个额外的程序集摘录证明 AddIn 程序集及其内部结构对测试可见。

My question is: why is this not working? I am pretty sure that this follows the generally accepted practices of VSTO testing.

如果以下不再可行,应该如何测试 VSTO? .NET remoting/IPC 是唯一的解决方案吗?

ThisAddin.cs

public partial class ThisAddin 
{
    #region Testing Utilities

    private AddinHelper _comAddinObject;

    protected override object RequestComAddInAutomationService()
    {
        // This is being called when I debug/run my project, but not when I run the tests
        return _comAddinObject ?? (_comAddinObject = new AddinHelper());
    }

    #endregion
}

#region Testing Utilities

[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IAddinHelper
{
    Presentation GetPresentation();
    string GetString();
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(IAddinHelper))]
public class AddinHelper : StandardOleMarshalObject, IAddinHelper
{
    public Presentation GetPresentation()
    {
        return Globals.ThisAddin... [...];
    }

    public string GetString()
    {
        return "Hello World!";
    }
}

#endregion

AssemblyInfo.cs

[assembly: InternalsVisibleTo("MyProject.Tests")]

MyUnitTest.cs(参考了MyProject

[TestClass]
public class BasicTest
{
    [TestMethod]
    public void TestInstantiates()
    {
        var application = new Application();
        var doc = application.Presentations.Open(@"C:\Presentation.pptx",
            MsoTriState.msoFalse, MsoTriState.msoFalse, MsoTriState.msoFalse);
        var comAddins = application.COMAddIns;
        var comAddin = comAddins.Item("MyProject"); // Returns okay
        var comObject = (IAddinHelper) comAddin.Object; // Exception occurs

        Assert.AreEqual(true, true); // Never reached

        doc.Close();
    }
}

此外,项目的设置设置为 "Register for COM interop" 并且 Visual Studio 运行时没有错误 - 运行 它作为非管理员导致 DLL 未被注册;因此,我也知道 COM 对象 注册的。

产生异常

An exception of type 'System.InvalidCastException' occurred in MyProject.Tests.dll but was not handled in user code Additional information: Unable to cast COM object of type 'System.__ComObject' to interface type 'MyProject.IAddinHelper'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{59977378-CC79-3B27-9093-82CD7A05CF74}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).

计算器溢出

微软

老实说,我不知道如何在没有此功能的情况下测试 VSTO 加载项。

解决方案

要测试方法的项目必须通过 .Net 参考 选项卡使用 PIA Microsoft.Office.Interop.PowerPoint。

在单元测试项目中,您必须通过 COM 引用 选项卡使用 Microsoft Powerpoint 1X.0 对象库 - 它是一个 ActiveX。

令人困惑的是在解决方案资源管理器中它们都被称为:Microsoft.Office.Interop.Powerpoint


当您指定正确的引用时,您会在发生异常的行上看到此错误:

Missing compiler required member 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create'

要解决这个问题,只需在单元测试项目中添加对 Microsoft.CSharp.dll 的 .Net 引用。


接下来我们将 运行 解决您看到的错误。

首先给界面添加一个唯一的GUID & class(这样可以克服错误):

[ComVisible(true)]
[Guid("B523844E-1A41-4118-A0F0-FDFA7BCD77C9")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IAddinHelper
{
    string GetPresentation();
    string GetString();
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("A523844E-1A41-4118-A0F0-FDFA7BCD77C9")]
[ComSourceInterfaces(typeof(IAddinHelper))]
public class AddinHelper : StandardOleMarshalObject, IAddinHelper

其次在范围 中临时创建 private AddinHelper _comAddinObject; public(您可以稍后在其工作时执行您的 [assembly: InternalsVisibleTo("MyProject.Tests")]).

第三,检查 Powerpoint 是否禁用了 COM 加载项。这有时会悄无声息地发生,没有 Office 应用程序的抱怨。

最后,确保勾选“为 COM 注册”。

中提琴:


参考: 几年前,我竭尽全力帮助这位 SO'r:Moq & Interop Types: works in VS2012, fails in VS2010?