简体   繁体   English

Moq和Interop类型:在VS2012中工作,在VS2010中失败?

[英]Moq & Interop Types: works in VS2012, fails in VS2010?

I have a .NET library project with about 500 unit tests. 我有一个.NET库项目,大约有500个单元测试。 All these tests run fine in Visual Studio 2012. However, some of my tests fail in Visual Studio 2010. In these failing tests, I use Moq to mock several Interop Types from Microsoft.Office.Interop.Excel . 所有这些测试在Visual Studio 2012中运行良好。但是,我的一些测试在Visual Studio 2010中失败。在这些失败的测试中,我使用MoqMicrosoft.Office.Interop.Excel模拟几个Interop类型。 The test fails immediately when attempting to access these mocked interop types: 尝试访问这些模拟的互操作类型时,测试立即失败:

Error: Missing method 'instance class Microsoft.Office.Interop.Excel.Range [ExcelAddIn.Core] Microsoft.Office.Interop.Excel.ListRow::get_Range()' from class 'Castle.Proxies.ListRowProxy'.

This exception implies that I forgot to setup the appropriate property getter on my mock. 这个异常意味着我忘了在mock上设置适当的属性getter。 Which is not the case: 事实并非如此:

_listRowMock.Setup(m => m.Range).Returns(_rangeMock.Object);

Now I can imagine that Moq might not work too well with Interop Types. 现在我可以想象Moq对于Interop类型可能效果不佳。 But what I find most puzzling is that these tests run fine in Visual Studio 2012, but fail in Visual Studio 2010. 但我发现最令人费解的是,这些测试在Visual Studio 2012中运行良好,但在Visual Studio 2010中失败。

Why is my Visual Studio influencing the behavior of my code? 为什么我的Visual Studio会影响我的代码行为?

UPDATE: 3-11-2012 更新:2012年3月11日

Ok, so I got it down to this: 好的,所以我明白了:

  • I have two projects; 我有两个项目; Core and Core.UnitTest. Core和Core.UnitTest。 Core is the actual library while Core.UnitTest is a unit test project of the Core library. Core是实际的库,而Core.UnitTest是Core库的单元测试项目。
  • Both projects reference Microsoft.Office.Interop.Excel with Embed Interop Types enabled. 这两个项目都引用了Microsoft.Office.Interop.Excel并启用了嵌入互操作类型。
  • Because EIT is enabled, both projects include their own "view" of the Microsoft.Office.Interop.Excel library. 由于启用了EIT,因此两个项目都包含自己的Microsoft.Office.Interop.Excel库“视图”。 The view includes all classes, methods and properties that are used in their respective project. 该视图包括其各自项目中使用的所有类,方法和属性。
  • Because both projects use different classes, methods and properties of the Microsoft.Office.Interop.Excel, the embedded types of both libraries differ. 由于两个项目都使用Microsoft.Office.Interop.Excel的不同类,方法和属性,因此两个库的嵌入类型不同。 Eg ListRow in Core has an Index and Range property, whereas ListRow in Core.UnitTest only has the Range property. 例如,Core中的ListRow具有Index和Range属性,而Core.UnitTest中的ListRow仅具有Range属性。
  • Although both types are different and do not share a common interface or super class, they are equivalent . 虽然两种类型都不同,并且不共享公共接口或超类,但它们是等效的 This means that the CLR will treat them as if they are the same and will allow you to use these types across assembly boundaries. 这意味着CLR会将它们视为相同,并允许您跨程序集边界使用这些类型。 Eg an instance of ListRow from Core.UnitTest will work fine when passed to a method in the Core library. 例如,Core.UnitTest中的ListRow实例在传递给Core库中的方法时可以正常工作。 The shared Range property will function, whereas the missing Index property will throw a MissingMethodException on access. 共享的Range属性将起作用,而缺少的Index属性将在访问时抛出MissingMethodException。
  • The aforementioned behavior even works with mocked types. 上述行为甚至适用于模拟类型。 An mocked object of Mock[Excel.ListRow] will work fine when crossing the assembly boundary. Mock [Excel.ListRow]的模拟对象在跨越装配边界时可以正常工作。
  • Unfortunately, the behavior described in the previous point only works when I build my assemblies in Visual Studio 2012 . 不幸的是,前一点中描述的行为仅在我在Visual Studio 2012中构建程序集时才有效。 When I build my assemblies in Visual Studio 2010 and debug my code, I can see the mocked ListRow instance being passed into a method of my Core project. 当我在Visual Studio 2010中构建程序集并调试我的代码时,我可以看到模拟的ListRow实例被传递到我的Core项目的方法中。 The moment the instance crosses the assembly boundary, all methods and properties of ListRow lose their implementation and throw MissingMethodExceptions. 实例越过程序集边界的那一刻,ListRow的所有方法和属性都会丢失它们的实现并抛出MissingMethodExceptions。
  • Now for the fun part, I actually managed to mitigate this issue by ensuring that both embedded types of ListRow are aligned. 现在,对于有趣的部分,我实际上通过确保两个嵌入类型的ListRow对齐来设法缓解此问题。 Eg in order for the compiler to create the same view of ListRow in both projects, I made sure that I used the exact same methods and properties in my UnitTest project. 例如,为了让编译器在两个项目中创建相同的ListRow视图,我确保在UnitTest项目中使用了完全相同的方法和属性。 This means adding dummy lines like: var dummy = listRow.Index. 这意味着添加虚拟行,如:var dummy = listRow.Index。 Once I had the compiler creating identical views of my embedded ListRow type, the instance was allowed to cross assembly boundaries without losing its implementation. 一旦我让编译器创建了我的嵌入式ListRow类型的相同视图,就允许该实例跨越程序集边界而不会丢失其实现。

The question still remains though: What causes this difference in behavior between Visual Studio 2010 and Visual Studio 2012? 问题仍然存在:是什么导致Visual Studio 2010和Visual Studio 2012之间的行为差​​异?

UPDATE: 9-11-2012 更新:2012年9月11日

Demo Solution : http://temp-share.com/show/KdPf6066h 演示解决方案http//temp-share.com/show/KdPf6066h

I have created a small solution to demonstrate the effect. 我已经创建了一个小解决方案来演示效果。 The solution consists of a library and a UnitTest project. 该解决方案由一个库和一个UnitTest项目组成。 Both reference Microsoft.Office.Interop.Excel.Range with EIT enabled. 两者都引用了Microsoft.Office.Interop.Excel.Range并启用了EIT。 The test works fine in VS2012 but throws MissingMethodException in VS2010. 该测试在VS2012中正常工作,但在VS2010中抛出MissingMethodException。 Uncommenting the dummy line in the test will make it work in VS2010. 在测试中取消注释虚拟线将使其在VS2010中工作。

FINAL UPDATE: 29-12-2012 最终更新:2012年12月29日

My apologies for the late update. 我为最新的更新道歉。 A colleague of mine found a solution, however I was unable to reproduce it on my machine. 我的一位同事找到了解决方案,但是我无法在我的机器上重现它。 In the meantime our company has made the switch to TFS2012 so this is no longer a blocking issue for me. 与此同时,我们公司已经转向TFS2012,因此这不再是我的阻塞问题。 The two most important conclusions my colleague made were: 我的同事做出的两个最重要的结论是:

  • The semantics of the "Any CPU" platform have changed from Visual Studio 2010 to Visual Studio 2012. This will result in different .DLL's being generated depending on whether you are using VS2010 or VS2012. “Any CPU”平台的语义已从Visual Studio 2010更改为Visual Studio 2012.这将导致生成不同的.DLL,具体取决于您使用的是VS2010还是VS2012。
  • Both projects referenced different versions of Microsoft.Office.Interop.Excel. 这两个项目都引用了Microsoft.Office.Interop.Excel的不同版本。

I checked my projects and straightened out the references, but it made no difference. 我检查了我的项目并理顺了参考文献,但没有任何区别。 After that, I tried different variations of platforms in both VS2010 and VS2012 but was unable to produce a satisfactory result. 之后,我在VS2010和VS2012中尝试了不同的平台变体,但无法产生令人满意的结果。 I will accept Jeremy's answer as it was the most helpful. 我会接受杰里米的回答,因为这是最有帮助的。 Thank you all for your assistance. 谢谢大家的帮助。

Edit : It works for me when I try it in Visual Studio 2012 and target .Net 4.0, only using the .Net PIA's not the COM ref. 编辑:当我在Visual Studio 2012中尝试并且目标.Net 4.0时,它适用于我,仅使用.Net PIA而不是COM参考。 Same solution doesn't work in VS2010. 相同的解决方案在VS2010中不起作用。

VS2010 loads version's 10.0.30319.1 of the Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll's and VS2012 loads version's 11.0.50727.1. VS2010加载版本10.0.30319.1的Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll's和VS2012加载版本11.0.50727.1。 You can see the different version's in the Modules window. 您可以在“模块”窗口中看到不同的版本。


I managed to get it working in VS2010: 我设法让它在VS2010中运行:

在此输入图像描述

Here is my solution http://temp-share.com/show/Pf3Ypip62 for everyone's convenience. 这是我的解决方案http://temp-share.com/show/Pf3Ypip62 ,方便大家。 It has all the Moq references included. 它包含所有Moq参考。 I have Excel 2007 (ie v12) - so please adjust references to Office 14. 我有Excel 2007(即v12) - 所以请调整对Office 14的引用。

The Project with methods to be Tested has to use the PIA Microsoft.Office.Interop.Excel via the .Net reference tab. 具有待测试方法的项目必须通过.Net参考选项卡使用PIA Microsoft.Office.Interop.Excel

In the Unit Test Project you have to use the Microsoft Excel 1X.0 Object Library via the COM reference tab - its an ActiveX. 在单元测试项目中,您必须通过COM参考选项卡使用Microsoft Excel 1X.0 Object Library - 它是一个ActiveX。

The confusing thing is in Solution Explorer they are both called: Microsoft.Office.Interop.Excel 令人困惑的是,在解决方案资源管理器中,它们都被称为:Microsoft.Office.Interop.Excel

There is one other caveat that I dont know how to workaround - you have to use the .Net 3.5 framework and I was actually hoping Microsoft fixed it in 2012 as you found because I cant work how to do it with ALL projects in .Net 4.0. 还有一个警告,我不知道如何解决方法 - 你必须使用.Net 3.5框架,我实际上希望微软在2012年修复它,因为我找不到 .Net 4.0中的所有项目如何做到这一点。 Some solutions with mixed projects targeting .Net 3.5 & 4.0 are ok. 针对.Net 3.5和4.0的混合项目的一些解决方案是可以的。

I've had a lot of trouble with this, see here How do I avoid using dynamic when mocking an Excel.worksheet? 我遇到了很多麻烦,请参阅此处如何在模拟Excel.worksheet时避免使用动态? and also see this question I asked: Mocked object doesn't have all properties shown in Intellisense - in one project but has them in the other . 并且我也问过这个问题: 模拟对象没有Intellisense中显示的所有属性 - 在一个项目中但在另一个项目中有它们

Anyway this is how to get it working in VS 2010. I'm glad its resolved in 2012! 无论如何,这是如何让它在VS 2010中运行。我很高兴它在2012年得到解决!

I tried to reproduce this, and for me it doesn't work even in VS 2012. 我试图重现这一点,对我而言,即使在VS 2012中它也不起作用。

When you compile a project using "Embed Interop Types", the C# compiler generates an internal type that has only the members you are accessing, and the implementation actually seems to use IDispatch to call the method of the COM object by id. 使用“嵌入互操作类型”编译项目时,C#编译器会生成一个只包含您正在访问的成员的内部类型,实现似乎实际上似乎使用IDispatch通过id调用COM对象的方法。

From your description I understand that your test project in VS 2012 does not access the properties (not even in order to mock them), but the test still succeeds and the generated type in the test project does have these members. 从您的描述中我了解到您在VS 2012 中的测试项目访问属性(甚至不是为了模拟它们),但测试仍然成功,测试项目生成的类型确实具有这些成员。

If this is indeed what you are experiencing, can you please look at the content of your test .dll and see how the interop type was generated? 如果您确实遇到了这种情况,请查看测试内容.dll并查看互操作类型是如何生成的? You can use a tool such as ildasm.exe . 您可以使用ildasm.exe等工具。

If the interop type in the test .dll contains all the members, even those you don't access in the test, this may give a clue that the difference is related to the way the interop types are generated in VS 2012. 如果测试.dll中的互操作类型包含所有成员,即使您在测试中未访问的成员,这可能会给出一个线索,即差异与VS 2012中生成互操作类型的方式有关。

Also, if you can attach a small minimal VS 2012 solution which reproduces the problem, it may greatly help in diagnosing this. 此外,如果您可以附加一个小的最小VS 2012解决方案来重现问题,它可能会有助于诊断这一点。

First of all check while adding library to the project in VS2010, make sure you created the mock object like 首先在VS2010中向库中添加库时进行检查,确保创建了模拟对象

Mock<DocumentService> _mock = new Mock<DocumentService>();

Also .NET 4.0 allows primary interop assemblies to be embedded into your assembly so that you don't need to deploy them alongside your application.Open the properties tab in the assembly in VS2010 and check the Embed Interop types.mkae sure its true. 此外,.NET 4.0允许将主互操作程序集嵌入到程序集中,这样您就不需要将它们与应用程序一起部署。在VS2010中打开程序集中的属性选项卡并检查嵌入式互操作类型.mkae确定它是真的。

And to instantiate excel, Excel.Application xlapp = new Excel.Application(); 并实例化excel, Excel.Application xlapp = new Excel.Application();

Hope it will work.. 希望它能起作用..

我发现,至少在VS2015中,我仍然可以在我测试的程序集中嵌入interop类型,但是在我的测试项目中将PIA程序集引用上的“Embed”设置为false,我没有重复这个。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 AppFabric DataCacheFactory()初始化在VS2013中挂起,在VS2010和VS2012中正常工作 - AppFabric DataCacheFactory() initialization hangs in VS2013, works fine in VS2010 and VS2012 System.Linq Linq查询无法在VS2012中工作,但在VS2010中可以正常工作 - System.Linq Linq queries not working in VS2012 but works fine in VS2010 如何在VS2010和VS2012中加载数据库项目? - How to load database project in VS2010 and VS2012? DeploymentItem在VS2010和VS2012中的行为方式不同 - DeploymentItem behaving differently in VS2010 and VS2012 VS2012 OutOfMemoryException与VS2010没有异常的工作 - VS2012 OutOfMemoryException vs. VS2010 working w/o Exception 无法在vs2012中打开vs2010 csproj文件 - can't open vs2010 csproj file in vs2012 将项目从VS2010迁移到VS2012后无法继承接口 - can't inherit interface after migrating project from VS2010 to VS2012 从VS2010移至VS2012后,HTML渲染间歇性丢失内容 - After move from VS2010 to VS2012 HTML rendering is intermittently losing content VS2010和VS2012的两个C#项目文件在同一目录中 - Two C# project files for VS2010 and VS2012 in the same directory 为什么数据驱动的单元测试在vs2012中在vs2010中正常工作时失败? - Why does data driven unit test fail in vs2012 when it worked fine in vs2010?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM