28

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

Brian Mains
  • 50,520
  • 35
  • 148
  • 257
Rodrigo Juarez
  • 1,745
  • 1
  • 23
  • 38
  • 4
    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 Feb 12 '12 at 20:47
  • 11
    Repository with DbContext is sometimes overkill ... – Rodrigo Juarez Mar 14 '12 at 01:41
  • 2
    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 Jun 21 '13 at 13:03

2 Answers2

38

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.

Anders Abel
  • 67,989
  • 17
  • 150
  • 217
Arthur Vickers
  • 7,503
  • 32
  • 26
5

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.

k.m
  • 30,794
  • 10
  • 62
  • 86
  • Hi, about the rebuild, I make some testing creating two separate projects, one with nuget for ef 4.2 and another with the ef 4.3, so I think that old code is not a problem. Anyway, what bothers me is that was working with ef 4.2 – Rodrigo Juarez Feb 12 '12 at 15:07
  • @RodrigoJuarez: you can use [ILSpy](http://wiki.sharpdevelop.net/ILSpy.ashx) to check EF 4.2 `CallValidateEntity` implementation. In EF 4.3 it's internal, so it can't be overriden. Why Moq is trying to do that anyways is beyond me. Maybe problem lies elsewhere. – k.m Feb 12 '12 at 15:11
  • the EF 4.2 code is the same, how can I see the metadata? Anyway, should I look for some problem in Moq? With the interface I have the problem solved, but I'm curious – Rodrigo Juarez Feb 12 '12 at 15:46
  • 1
    @RodrigoJuarez: check [this answer](http://stackoverflow.com/questions/8861065/what-is-metadata-in-net/8861655#8861655) to see how to view metadata. Did your EF 4.2 project exposed its internals to Moq, say via `InternalsVisibleTo` attribute in *AssemblyInfo.cs*? – k.m Feb 12 '12 at 15:49
  • I don't think so, the AssemblyInfo.cs is the default for a class library project, Visual Studio 2010 net 4 – Rodrigo Juarez Feb 12 '12 at 20:15
  • and here is the metadata Method #20 (060004aa) ------------------------------------------------------- MethodName: CallValidateEntity (060004AA) Flags : [Assem] [Virtual] [HideBySig] [NewSlot] (000003c3) – Rodrigo Juarez Feb 12 '12 at 20:25
  • @RodrigoJuarez: it must be EF 4.3 issue. I tried to reproduce it with other class and Moq works just fine. What exactly causes error and why it got broken in 4.3, I have no clue... – k.m Feb 12 '12 at 20:36