Fixture.CreateAnonymous method kills test runner process with an error (AutoFixture) when using AutoMoq to create a Controller

不打扰是莪最后的温柔 提交于 2019-12-06 15:00:23

Suggested solution

To start with a possible solution, this should stop the crashing:

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>();

Explanation

And now for the explanation:

This test error is caused by AutoFixture's AutoProperties feature trying to assign a value to HomeController.ViewData.ModelMetaData. The ModelMetaData class has this constructor:

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

The culprit here is the modelAccessor parameter. To fill that property AutoFixture (rather mindlessly) reflects over the type and finds this single constructor:

public Func(object @object, IntPtr method)

Digging further, the first IntPtr constructor AutoFixture can satisfy is this one:

public unsafe IntPtr(int value)

By default, Int32 instances are created by a deterministic rising sequence, so value in this case will probably be 1 or 2 or a similar small integer. In other words, we now have a very invalid unsafe pointer on our hands, and this is making the process crash.

Now, under normal circumstances we should be able to fix this by registering a Func<object> with the Fixture and everything should be dandy:

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

However, I tried this with your repro and although the process no longer crashes in the same way, the test runs for a very long time and finally crashes with an OutOfMemoryException.

I don't know what ASP.NET MVC does with Func<object>, but apparently it uses it quite heaviliy.

The question remains whether this is a bug in AutoFixture?

I believe that it isn't. While it is definitely less than ideal, AutoFixture doesn't treat Funcs or Actions any differently than other types, which is why we see this behavior.

This particular behavior could possibly be addressed by adding specific support for Func<TResult>, but to stay consistent it should also have support for Func<T, TResult>, Func<T1, T2, TResult>, etc. AFAIR in .NET 4 there are a lot of these delegate types (also Action, etc.), so that would mean adding support for a whole host of types.

But then what about all other types that take an IntPtr in their constructor? AutoFixture can't possibly know about them all, so this seems not like a viable direction.

However, what it could have is a guard that prevents it from attempting to create IntPtr instances in the first place. This will most likely be added before the 2.0 RTW.

Thank you for reporting this.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!