10

我正在尝试使用 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 项目中工作。

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

谢谢!

4

2 回答 2

5

VS2012 更新:起订量 和互操作类型:在 VS2012 中有效,在 VS2010 中失败?

首先:发生了一些变化: 在模拟 Excel.worksheet 时如何避免使用动态?

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


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

您可以离开面向 .Net 4.0 的测试项目,但您需要将 VSTO 项目 .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 vs 4.0 语法错误。不要忘记删除dynamic参数类型并将其替换为原始Worksheet. 最后再次启动测试,它会通过!!!

鉴于我在此线程中对 Microsoft.CSharp.DLL 所经历的所有悲痛,我认为使用 Mocking Frameworks 测试 VSTO .Net 4.0 项目不起作用。

于 2012-09-25T04:41:45.340 回答
-1

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

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

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

于 2012-08-20T18:47:25.097 回答