views:

31

answers:

1

I'm trying to use the AutoMoqCustomization with AutoFixture to create an ASP.NET MVC2 Controller in a unit test via the Fixture.CreateAnonymous method. I've tried in both xUnit under TestDriven.NET, the xUnit test GUI and in MSTest and all have the same result: a massive failure of the process running the test. On Windows 7 x64 if that matters.

To reproduce, simply create a new ASP.NET MVC2 project, add the references to AutoFixture, AutoMoq and Moq (3.1, as per the AutoMoq source) and try the below (repro VS2010 MVC2 project link below):

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

In MSTest the error reads:

The runtime has encountered a fatal error. The address of the error was at 0x6465f370, on thread 0x2684. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.

AfWithMvc repro project (from SkyDrive)

+2  A: 

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.

Mark Seemann
Thanks, that's an excellent explanation and fix. For what it's worth, I agree with your idea that IntPtr should be guarded, but no delegate-specific support should be added - seems unnecessary.
ZeroBugBounce
Ok, I played around with fixture.Inject<Func<object>>(..) and between that and MVC2 source, figured out that the MVC framework requires null to be returned at some point from that Func<object> as a terminator/signal. It can be return null from the start or return n strings and then null.
ZeroBugBounce