绑定到Excel应用程序事件时出现MissingMethodException

时间:2014-04-15 16:33:22

标签: c# excel unit-testing vsto moq

我正在尝试为我创建的Excel VSTO加载项创建单元测试,但我遇到了一个令人难以置信的神秘问题,感觉远远超出了我的经验。

在这种情况下,我有一位演示者:

public class Presenter
{
  private readonly Excel.Application Application;

  public Presenter(Excel.Application Application)
  {
    this.Application = Application;

    Application.WorkbookActivate += Application_WorkbookActivate;
  }

  private void Application_WorkbookActivate(Excel.Workbook Wb)
  {
    // logic to be tested
  }
}

我的单元测试是验证调用WorkbookActivate时,它会执行特定的操作,例如:

[Test]
public void TestLogicWhenWorkbookActivates()
{
  var mockApplication = new Mock<Excel.Application>();

  presenter = new Presenter(mockApplication.Object);

  // Act
  mockApplication.Raise(a => a.WorkbookActivate += null, (Excel.Workbook)null);

  // Assert
  // ...
}

现在,当我运行此测试时,它在添加事件时失败(发生在演示者的构造函数中),抛出以下内容:

System.MissingMethodException : Error: Missing method 'instance void [ExcelAddIns.TestControl] Microsoft.Office.Interop.Excel.AppEvents_Event::add_WorkbookActivate(class Microsoft.Office.Interop.Excel.AppEvents_WorkbookActivateEventHandler)' from class 'Castle.Proxies.ApplicationProxy'.

我的理解,基于this related Stack Overflow post,我所执行的是第三方回调,并且在Moq 4.0之前失败了。我使用的是Moq 4.2.1402.2112。

所以这里有一个奇怪的部分:在Stack Overflow的回答中,提到了Moq错误报告,该报告拥有一个单元测试来测试这个概念:

[Test]
public void InteropExcelTest()
{
  var mockAppExcel = new Mock<Excel.Application>();

  bool isDelegateCalled = false;

  mockAppExcel.Object.WorkbookActivate += delegate { isDelegateCalled = true; };

  mockAppExcel.Raise(ae => ae.WorkbookActivate += null, (Excel.Workbook)null);

  Assert.True(isDelegateCalled);
}

这个测试确实通过了,这意味着我的第一个测试应该是有效的,因为它正确处理事件。但更奇怪的是,将此测试包含在我的单元测试.cs文件中会导致先前失败的测试(TestLogicWhenWorkbookActivates)通过!

这些测试完全独立。为什么第二个存在导致第一个通过?

1 个答案:

答案 0 :(得分:1)

经过一些额外的研究和实验,我相信我已经解决了我的问题。我不是互操作专家,所以如果我在这里做出任何错误的结论,请随时编辑或更正我。

我正在处理两个项目:

  • ExcelAddIns.TestControl
  • ExcelAddIns.TestControl.Tests

两者都需要VSTO引用(包括Microsoft.Office.Interop.Excel等)。所有VSTO引用都将Embed Interop Types设置为true(我认为这是默认值)。基于我所阅读的内容(参见下面的参考资料),这是问题的关键,因为它有效地将组件分开了。嵌入式类型,当我的单元测试引用TestControl项目时导致冲突。

因此,对于两个项目中的所有VSTO程序集引用,我的解决方案是Embed Interop Types设置为false 。这导致单元测试在没有第二次测试的情况下通过。

参考文献:

Stack Overflow: Moq & Interop Types: works in VS2012, fails in VS2010?

Stack Overflow: What's the difference setting Embed Interop Types true and false in Visual Studio?

Daniel Cazzulino's Blog: Check your Embed Interop Types flag when doing Visual Studio extensibility work