实体框架4.3和Moq无法创建DbContext模拟对象

28

下面这个在EF 4.2中工作的测试,在EF 4.3中抛出了以下异常:

System.ArgumentException:模拟类型必须是接口、抽象类或非密封类。----> System.TypeLoadException:程序集“DynamicProxyGenAssembly2,版本 = 0.0.0.0,Culture = neutral,PublicKeyToken = null”中的类型“Castle.Proxies.DbContext43Proxy”的方法“CallValidateEntity”正在覆盖一个不可见的方法。

[Test]
public void CanCreateMoqTest()
{
    // Arrange
    Mock<DbContext43> mock;

    // Act
    mock = new Mock<DbContext43>();

    // Assert
    Assert.NotNull(mock.Object);
}

public class DbContext43:DbContext
{
}

我该怎么办?为我的DbContext43创建一个接口?

这是4.2和4.3之间的破坏性变更吗?

谢谢!!


4
使用仓储和工作单元模式,您将不会遇到这个问题。您还可以避免将所有代码与 EF 耦合在一起。 - TrueWill
11
使用带有DbContext的仓库有时会过度设计... - Rodrigo Juarez
2
我曾经深入研究过将我的EF代码封装在仓储模式中。最终你会创建自己的数据访问框架,这需要更多的维护时间,而我不想承认这一点。除非你正在构建一个企业框架,可以由多个团队共享,并且你有一个专门负责维护基础设施的团队,否则我建议不要将EF封装在仓储模式中。 - William Edmondson
2个回答

38

感谢你找到了这个问题。问题是由我们在EF 4.2版本中剥离的InternalsVisibleTo属性导致的,但是我们在EF 4.3版本中保留了它。这使得我们在测试中使用的Moq能够看到EntityFramework.dll的内部。然而,由于您的程序集无法看到那些内部实现,所以您遇到了异常。

我们计划在接下来几周内发布EF 4.3的补丁版本,并将删除InternalsVisibleTo,此后模拟将再次正常工作。

更新:已经在今天发布的EF 4.3.1(和EF 5.0-beta1)中修复了此问题。更新NuGet包即可获取修复程序。有关详情,请参见http://blogs.msdn.com/b/adonet/archive/2012/02/29/ef4-3-1-and-ef5-beta-1-available-on-nuget.aspx


所以在这些修复到来之前,我将降级到Entity Framework 4.2 :( - Ashraf Alam
1
非常感谢你,Arthur!没想到Moq问题会这么快得到解决,超出了我的预期! - Ashraf Alam

5
这种异常通常表示您尝试覆盖的成员在给定程序集的公共接口中未公开(或者更准确地说 - 覆盖程序集无法看到它)。如果我们看一下EntityFramework 4.3中的CallValidateEntity实现:
internal virtual DbEntityValidationResult CallValidateEntity(
    DbEntityEntry entityEntry, IDictionary<object, object> items)
{
    return this.ValidateEntity(entityEntry, items);
}

我们确实注意到这个方法是internal的,因此属于不可重写的类别(非重写,因为没有使用InternalsVisibleTo属性)。这自然需要正确的元数据条目:

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

对于Moq尝试重写该成员的原因还不太清楚...考虑到它首先不应该看到它。

将您的上下文包装在接口中,并仅公开实际使用的方法是可行的选择-这应该足以使您的测试通过。


@RodrigoJuarez:你可以使用ILSpy来检查EF 4.2的CallValidateEntity实现。在EF 4.3中,它是内部的,因此无法被覆盖。为什么Moq还要尝试这样做,这超出了我的理解范围。也许问题出在其他地方。 - k.m
EF 4.2代码是相同的,我该如何查看元数据?不管怎样,我应该在Moq中寻找一些问题吗?通过接口,我已经解决了这个问题,但我很好奇。 - Rodrigo Juarez
1
@RodrigoJuarez:查看这个答案以了解如何查看元数据。你的EF 4.2项目是否通过AssemblyInfo.cs中的InternalsVisibleTo属性向Moq公开了其内部? - k.m

以下是元数据方法#20 (060004aa)

方法名称: CallValidateEntity (060004AA) 标志 : [Assem] [Virtual] [HideBySig] [NewSlot] (000003c3)
- Rodrigo Juarez
@RodrigoJuarez:这一定是EF 4.3的问题。我尝试使用其他类进行复制,Moq运行良好。关于具体是什么原因导致错误以及为什么在4.3中出现故障,我一无所知... - k.m
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接