3

我正在尝试使用 AutoMoqCustomization 和 AutoFixture 在单元测试中通过 Fixture.CreateAnonymous 方法创建一个 ASP.NET MVC2 控制器。我在 TestDriven.NET 下的 xUnit、xUnit 测试 GUI 和 MSTest 中都进行了尝试,结果都相同:运行测试的进程出现大规模故障。如果重要的话,在 Windows 7 x64 上。

要重现,只需创建一个新的 ASP.NET MVC2 项目,添加对 AutoFixture、AutoMoq 和 Moq 的引用(3.1,根据 AutoMoq 源)并尝试以下操作(下面的重现 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<HomeController>();
}

在 MSTest 中,错误显示为:

运行时遇到致命错误。错误地址位于线程 0x2684 上的 0x6465f370。错误代码为 0xc0000005。此错误可能是 CLR 中的错​​误或用户代码的不安全或不可验证部分中的错误。此错误的常见来源包括 COM 互操作或 PInvoke 的用户封送错误,这可能会损坏堆栈。

AfWithMvc 复制项目(来自 SkyDrive)

4

1 回答 1

4

建议的解决方案

从一个可能的解决方案开始,这应该会阻止崩溃:

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

HomeController controller = fixture.CreateAnonymous<HomeController>();

解释

现在解释一下:

此测试错误是由 AutoFixture 的AutoProperties功能试图为HomeController.ViewData.ModelMetaData. ModelMetaData 类有这个构造函数:

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

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

public Func(object @object, IntPtr method)

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

public unsafe IntPtr(int value)

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

现在,在正常情况下,我们应该能够通过Func<object>向 Fixture 注册 a 来解决此问题,并且一切都应该是花花公子:

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

但是,我用您的复制品尝试了这个,虽然该过程不再以相同的方式崩溃,但测试运行了很长时间,最终崩溃并出现 OutOfMemoryException。

我不知道 ASP.NET MVC 对 ASP.NET MVC 做了什么Func<object>,但显然它使用得非常频繁。

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

我相信它不是。虽然它绝对不够理想,但 AutoFixture 对待 Funcs 或 Action 的方式与其他类型没有任何不同,这就是我们看到这种行为的原因。

这种特殊的行为可以通过添加对 的特定支持来解决Func<TResult>,但为了保持一致,它还应该支持Func<T, TResult>,Func<T1, T2, TResult>等。AFAIR 在 .NET 4 中有很多这样的委托类型(还有 Action 等),所以意味着增加对一大堆类型的支持。

但是,所有其他在其构造函数中采用 IntPtr 的类型呢?AutoFixture 不可能知道所有这些,所以这似乎不是一个可行的方向。

然而,它可能拥有的是一个防止它首先尝试创建 IntPtr 实例的守卫。这很可能会在 2.0 RTW 之前添加。

感谢您报告此事。

于 2010-08-18T19:57:13.470 回答