Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework 4.3 and Moq can't create DbContext mock

The following test that was working with EF 4.2 now throws the next exception with EF 4.3

System.ArgumentException : Type to mock must be an interface or an abstract or non-sealed class. ----> System.TypeLoadException : Method 'CallValidateEntity' on type 'Castle.Proxies.DbContext43Proxy' from assembly 'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is overriding a method that is not visible from that assembly.

[Test] public void CanCreateMoqTest() {     // Arrange     Mock<DbContext43> mock;      // Act     mock = new Mock<DbContext43>();      // Assert     Assert.NotNull(mock.Object); }  public class DbContext43:DbContext { } 

What should I do? Create an interface for my DbContext43?

Is this a breaking change between 4.2 and 4.3?

Thanks!!

like image 505
Rodrigo Juarez Avatar asked Feb 12 '12 00:02

Rodrigo Juarez


2 Answers

Thanks for finding this. The problem is caused by the the InternalsVisibleTo attributes that we stripped out of the EF 4.2 release but left in for the EF 4.3. This allowed Moq (which we use for our tests) to see the internals of EntityFramework.dll. However, since your assembly cannot see those internals you ended up with the exception.

We plan to do a patch release of EF 4.3 in the next few weeks and will be stripping InternalsVisibleTo out of this release after which mocking should work again.

Update: This is now fixed in EF 4.3.1 (and EF 5.0-beta1) released today. Update your NuGet package to get the fix. See http://blogs.msdn.com/b/adonet/archive/2012/02/29/ef4-3-1-and-ef5-beta-1-available-on-nuget.aspx for details.

like image 92
Arthur Vickers Avatar answered Sep 18 '22 09:09

Arthur Vickers


This kind of exception usually indicates member you're trying to override is not exposed as part of public interface in the given assembly (or perhaps to be more precise - overriding assembly does not see it). And if we take a look at CallValidateEntity implementation in EntityFramework 4.3:

internal virtual DbEntityValidationResult CallValidateEntity(     DbEntityEntry entityEntry, IDictionary<object, object> items) {     return this.ValidateEntity(entityEntry, items); } 

We indeed notice that this method is internal, and as a result falls in the non-overridable category (non-overridable considering no InternalsVisibleTo attribute is used). This is naturally matched by proper metadata entry:

Method #20 (06000a03) -------------------------------------------------------   MethodName: CallValidateEntity (06000A03)   Flags     : [Assem] [Virtual] [HideBySig] [NewSlot]  (000003c3) 

It's rather unclear why Moq attempts to override that member... considering it shouldn't see it in first place.

Wrapping your context in an interface and exposing only methods you actually use is a viable option - it should be enough to get your test passing.

like image 33
k.m Avatar answered Sep 18 '22 09:09

k.m