在模拟Excel.worksheet时如何避免使用动态?

时间:2012-06-01 01:03:53

标签: c# excel mocking vsto nsubstitute

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

那是怎么回事,做这样的事情最好的方法是什么?

谢谢!

2 个答案:

答案 0 :(得分:4)

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时,您需要检查嵌入互操作类型属性是否可见。如果这意味着你的目标.Net 4.0(我可以从动态关键字猜测)。

  

您可以将测试项目保留为.Net 4.0但您需要   将VSTO Project .Net框架更改回3.5。然后你会的   可能必须做一些明确的演员并完全符合要求   摆脱这些错误:

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

.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。最后再次启动测试,它将通过!!!

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

答案 1 :(得分:-1)

事实证明,使用任何基于城堡的框架(nsubstitute,ninject等)模拟非常复杂的COM互操作对象(如Excel对象或InDesign对象)并不能提供足够的性能启动。测试的运行时间仍可在几秒内测量。 (通过数十或数百次测试得出这一点,使得单元测试仍然太慢,无法在TDD测试原则下持续运行。)

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

对Excel和应用程序之间的抽象层进行测试可以快速测试应用程序逻辑。在集成测试下测试抽象层到excel应该足以彻底测试应用程序。