使用AutoMoq创建控制器时,Fixture.CreateAnonymous方法使用错误(AutoFixture)杀死测试运行程序进程

我正在尝试使用AutoMoqCustomization和AutoFixture通过Fixture.CreateAnonymous方法在unit testing中创建ASP.NET MVC2控制器。 我在TestDriven.NET下的xUnit,xUnit测试GUI和MSTest中都尝试过,并且都有相同的结果:运行测试的过程发生了大量故障。 在Windows 7 x64上,如果这很重要。

要重现,只需创建一个新的ASP.NET MVC2项目,添加对AutoFixture,AutoMoq和Moq(3.1,根据AutoMoq源)的引用,并尝试下面的(下面的repro VS2010 MVC2项目链接):

[TestMethod] public void Index() { var fixture = new Fixture().Customize(new AutoMoqCustomization()); // here's where the error in the test host occurs: HomeController controller = fixture.CreateAnonymous(); } 

在MSTest中,错误如下:

运行时遇到了致命错误。 错误的地址是0x6465f370,位于线程0x2684。 错误代码是0xc0000005。 此错误可能是CLR中的错误,也可能是用户代码的不安全或不可validation部分中的错误。 此错误的常见来源包括COM-interop或PInvoke的用户封送错误,这可能会破坏堆栈。

AfWithMvc repro项目(来自SkyDrive)

建议的解决方案

要从可能的解决方案开始,这应该停止崩溃:

 var fixture = new Fixture().Customize(new AutoMoqCustomization()); // This should fix the problem for all Controllers fixture.Customize(c => c.Without(x => x.ModelMetadata)); HomeController controller = fixture.CreateAnonymous(); 

说明

现在解释一下:

此测试错误是由AutoFixture的AutoPropertiesfunction尝试为HomeController.ViewData.ModelMetaData分配值引起的。 ModelMetaData类具有以下构造函数:

 public ModelMetadata( ModelMetadataProvider provider, Type containerType, Func modelAccessor, Type modelType, string propertyName) 

这里的罪魁祸首是modelAccessor参数。 为了填充该属性,AutoFixture(相当无意识地)反映了该类型并找到了这个单一的构造函数:

 public Func(object @object, IntPtr method) 

进一步挖掘,第一个IntPtr构造函数AutoFixture可以满足这一个:

 public unsafe IntPtr(int value) 

默认情况下, Int32实例由确定性上升序列创建 ,因此在这种情况下, value可能是1或2或类似的小整数。 换句话说,我们现在手上有一个非常无效的不安全指针,这使得进程崩溃。

现在,在正常情况下,我们应该能够通过使用Fixture注册Func来解决这个问题,一切都应该是花花公子:

 fixture.Register>(() => () => new object()); 

但是,我尝试使用你的repro,尽管进程不再以相同的方式崩溃,但测试运行了很长时间,最后崩溃并出现OutOfMemoryException。

我不知道ASP.NET MVC使用Func做了什么,但显然它使用它非常重。

问题仍然是这是否是AutoFixture中的错误?

我相信事实并非如此。 虽然它绝对不太理想,但AutoFixture并不会将Funcs或Actions与其他类型区别对待,这就是我们看到这种行为的原因。

这种特殊行为可以通过添加对Func特定支持来解决,但为了保持一致,它还应该支持FuncFunc等.AFFI在.NET 4中有很多这些委托类型(也是Action等),因此这意味着要添加对整个类型的支持。

但那么在构造函数中采用IntPtr的所有其他类型呢? AutoFixture可能无法全部了解它们,所以这似乎不是一个可行的方向。

但是,它可能具有的防护措施可以防止它首先尝试创建IntPtr实例 。 这很可能会在2.0 RTW之前添加。

感谢您报告此事。