28
votes

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!!

2
Use the Repository and Unit of Work patterns and you won't have this problem. You also won't couple all of your code to EF.TrueWill
Repository with DbContext is sometimes overkill ...Rodrigo Juarez
I have been deep down the route of wrapping my EF code in a repository pattern. You end up creating your own data access framework which ultimately takes more time in maintenance than I care to admit. Unless you are building an enterprise framework to be shared by several teams and you have a team dedicated to maintaining the infrastructure I would recommend staying away from wrapping EF in a repository pattern.William Edmondson

2 Answers

38
votes

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.

5
votes

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.