【问题标题】:How do I avoid using dynamic when mocking an Excel.worksheet?模拟 Excel.worksheet 时如何避免使用动态?
【发布时间】:2012-06-01 01:03:53
【问题描述】:

我正在尝试使用 NSubstitute 或其他模拟框架和 MSTest (Visual Studio 2010) 模拟 Excel 电子表格。我不确定是否有比这更好的方法——而且这对测试不太有效:

这里是一个例子(现在都是原型代码,不是很干净):

int[] lowerBounds = { 1, 1 };
int[] lengths = { 2, 2 };

//Initialize a 1-based array like Excel does:
object[,] values = (object[,])Array.CreateInstance(typeof(object), lengths, lowerBounds);
values[1,1] = "hello";
values[2,1] = "world";      

//Mock the UsedRange.Value2 property
sheet.UsedRange.Value2.Returns(values); 

//Test:   
GetSetting(sheet, "hello").Should().Be("world");  //FluentAssertions

到目前为止,一切顺利:如果 GetSetting 方法与我的测试在同一个项目中,则通过。但是,当 GetSetting 在我的 VSTO Excel-Addin 项目中时,它会在 GetSetting 函数的第一行出现以下错误:

System.MissingMethodException: Error: Missing method 'instance object [MyExcel.AddIn] Microsoft.Office.Interop.Excel.Range::get_Value2()' from class 'Castle.Proxies.RangeProxy'.

作为参考,GetSetting 从工作表中的 columnA 中获取一个值,并返回 columnB 中的值。

public static string GetSetting(Excel.Worksheet sheet, string settingName) {
  object[,] value = sheet.UsedRange.Value2 as object[,];
  for (int row = 1; row <= value.GetLength(1); row++) {
    if (value[1, row].ToString() == settingName)
      return value[2, row].ToString();
  }
  return "";
}

最后一个有趣的部分是如果我重新定义我的方法的签名如下:
public static string GetSetting(dynamic sheet, string settingName)
它适用于 VSTO 项目。

那么发生了什么,做这种事情的最佳方法是什么?

谢谢!

【问题讨论】:

  • 这听起来像是一个缺少引用的情况。
  • 运行测试时,bin目录下的microsoft.office.tools.excel.dll是否存在?
  • 就我而言,在我的测试项目(在我的情况下为 Microsoft.Office.Interop.Word)中为 DLL 关闭“嵌入互操作类型”并打开“本地复制”解决了该错误。谢谢。

标签: c# excel mocking vsto nsubstitute


【解决方案1】:

VS2012 更新: Moq & Interop Types: works in VS2012, fails in VS2010?

首先:发生了一些变化: How do I avoid using dynamic when mocking an Excel.worksheet?

我在使用 NSubstitute 模拟 Excel 对象时遇到了同样的问题。正如您提到的那样,动态解决了问题。但是我想找到根本原因。


当您的项目引用 Microsoft.Office.Interop.Excel.Extensions.dll 时,您需要检查 Embed Interop Types 属性是否可见。如果是这样,则意味着您的目标是 .Net 4.0(我可以从 dynamic 关键字中猜到)。

您可以离开针对 .Net 4.0 的测试项目,但您需要自己 将 VSTO Project .Net 框架改回 3.5。然后你会 可能必须做一些明确的转换并完全限定事情 摆脱这些错误:

C# Office Excel 互操作“对象不包含定义”错误,以下是几个示例:

.Net 4.0:

if (tmpsheetName == xlApp.ActiveSheet.Name)

.Net 3.5 等效

Worksheet activeSheet = (Worksheet)xlApp.ActiveSheet;
if (tmpsheetName == activeSheet.Name)

另一个例子:

rn.Select();

.Net 4.0

xlApp.Selection.HorizontalAlignment = Constants.xlCenter; 
xlApp.Selection.Font.Bold = true;
xlApp.Selection.Merge();

.Net 3.5 等效

rn.HorizontalAlignment = Constants.xlCenter;
rn.Font.Bold = true;
rn.Merge();

按照上述示例继续修复所有 .Net 3.5 和 4.0 语法错误。不要忘记删除dynamic 参数类型并将其替换为原始Worksheet。最后再次启动测试,它会通过!!!

考虑到我在 thread 中对 Microsoft.CSharp.DLL 的所有痛苦,我认为使用 Mocking Frameworks 测试 VSTO .Net 4.0 项目不起作用。

【讨论】:

  • 感谢您分享您的经验和解决方法!对此,我真的非常感激!测试性能如何?
  • 非常有趣。感谢更新!!现在我只需要升级VS2012!
  • @JeremyThompson 我试图弄清楚如何对文档级插件进行单元测试,听起来您对 VSTO 世界中的单元测试了解很多。您是否有博客或任何关于此主题的文章?
  • 嗨,克里斯,我没有,如果您有问题,请提出新问题并在此处发布链接,我会看看
【解决方案2】:

事实证明,使用任何基于城堡的框架(nsubstitute、ninject 等)模拟非常复杂的 COM 互操作对象(例如 Excel 对象或 InDesign 对象)并不能提供足够的性能启动。测试的运行时间仍然可以以秒为单位进行测量。 (将其乘以数十或数百个测试会使单元测试仍然太慢而无法在 TDD 不断测试的原则下运行。)

测试 Excel 逻辑应被视为集成测试,因此,针对实际 Excel 对象运行应该没问题,在这种情况下模拟不是很有用。结果将是针对实际对象的更有用的测试。

测试放置在 Excel 和应用程序之间的抽象层将允许快速测试应用程序逻辑。在集成测试下测试从抽象层到 Excel 应该足以彻底测试应用程序。

【讨论】:

  • 这不能回答问题。只是根据用户的体验给出一个有趣的假设。没有代码示例,其他答案恕我直言应该被接受。
猜你喜欢
  • 1970-01-01
  • 2016-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-10
相关资源
最近更新 更多