VSTO单元测试通过RequestComAddInAutomationService在C#.NET中添加Office

JDR*_*JDR 6 c# com testing vsto office-interop

在过去的几周里,我一直在阅读各种StackOverflow问题和其他教程和文档(请参阅下面的一些内容),试图找到一种单元测试VSTO AddIn的方法.

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

我正在使用的代码如下 - 一个OverAdiding的ThisAddin部分类的提取RequestComAddinAutomationService,另一个描述测试实用程序接口,测试本身,以及一个额外的程序集提取,证明AddIn程序集及其内部对测试可见.

我的问题是:为什么这不起作用?我很确定这遵循VSTO测试的普遍接受的做法.

如果以下不再可能,那么应该如何测试VSTO?.NET远程处理/ 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
Run Code Online (Sandbox Code Playgroud)

AssemblyInfo.cs中

[assembly: InternalsVisibleTo("MyProject.Tests")]
Run Code Online (Sandbox Code Playgroud)

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

此外,项目的设置设置为"注册COM互操作"并且Visual Studio运行升级而没有错误 - 将其作为非管理员运行导致DLL未注册; 因此,我也知道COM对象注册.

结果异常

MyProject.Tests.dll中出现"System.InvalidCastException"类型的异常但未在用户代码中处理附加信息:无法将"System .__ ComObject"类型的COM对象强制转换为接口类型"MyProject.IAddinHelper".此操作失败,因为对于具有IID"{59977378-CC79-3B27-9093-82CD7A05CF74}"的接口的COM组件的QueryInterface调用由于以下错误而失败:不支持此类接口(HRESULT异常:0x80004002(E_NOINTERFACE)) .

堆栈溢出

微软

老实说,我不知道在没有这个工作的情况下应该如何测试VSTO加载项.

Jer*_*son 7

解决方案

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

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

在此处输入图片说明

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


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

缺少编译器所需的成员“Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create”

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


接下来我们将遇到您所看到的错误。

首先向接口和类添加一个唯一的 GUID (这将克服错误):

[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
Run Code Online (Sandbox Code Playgroud)

其次,暂时private AddinHelper _comAddinObject;在 Scope 中公开(您可以稍后在其工作时进行 [assembly: InternalsVisibleTo("MyProject.Tests")] )

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

在此处输入图片说明

最后,确保注册 COM 被勾选。

中提琴:

在此处输入图片说明


参考:我几年前就开始解决这个问题了 SO'r: Moq & Interop Types: 在 VS2012 中工作,在 VS2010 中失败?

  • 杰里米,你成就了我的一周!非常感谢 - 这很有魅力,我现在的幸福程度是无法言喻的。我也是,为此一直在拔头发,留了一会儿,然后又开始沉迷于它。再次感谢! (2认同)