【问题标题】:How can I fake a DbSet<T> using FakeItEasy when the classes are internal?当类是内部的时,如何使用 FakeItEasy 伪造 DbSet<T>?
【发布时间】:2014-07-27 20:33:43
【问题描述】:

我正在使用 Entity Framework 6 并希望对我的一些业务逻辑代码进行单元测试。按照 Microsoft 的示例说明如何执行此操作,他们使用 MOQ 提供以下示例:

var mockSet = new Mock<DbSet<Blog>>(); 

var mockContext = new Mock<BloggingContext>(); 
mockContext.Setup(m => m.Blogs).Returns(mockSet.Object); 

var service = new BlogService(mockContext.Object); 

我正在使用FakeItEasy 而不是MOQ,我希望它会一样简单,但是FakeItEasy 抱怨它不能使用以下方法创建我的DbSet 的假冒:

var fakeDbSet = A.Fake<DbSet<InstalledProduct>>();

我得到一个异常如下:

FakeItEasy.Core.FakeCreationException:无法创建假的 输入“TN.Prs.Persistence.LicenseContext”。

以下是每个尝试的构造函数失败的原因列表: 没有构造函数参数失败: 在 TN.Prs.Persistence.LicenseContext 类型上找不到可用的默认构造函数。 在此调用期间捕获了异常。它的信息是: 访问被拒绝:'TN.Prs.Persistence.LicenseContext'。

在 FakeItEasy.Core.DefaultExceptionThrower.ThrowFailedToGenerateProxyWithResolvedConstructors(类型 typeOfFake, String reasonForFailureOfUnspecifiedConstructor, IEnumerable1 resolvedConstructors) at FakeItEasy.Creation.FakeObjectCreator.TryCreateFakeWithDummyArgumentsForConstructor(Type typeOfFake, FakeOptions fakeOptions, IDummyValueCreationSession session, String failReasonForDefaultConstructor, Boolean throwOnFailure) at FakeItEasy.Creation.FakeObjectCreator.CreateFake(Type typeOfFake, FakeOptions fakeOptions, IDummyValueCreationSession session, Boolean throwOnFailure) at FakeItEasy.Creation.DefaultFakeAndDummyManager.CreateFake(Type typeOfFake, FakeOptions options) at FakeItEasy.Creation.DefaultFakeCreatorFacade.CreateFake[T](Action1 选项)在 FakeItEasy.A.FakeT TN.Prs.RegistrationServices.Specifications.when_activating_a_product_from_a_valid_digitally_signed_activation_key.<.ctor>b__0() 在

我的 POCO 类是 internal 而不是 public,但我已根据需要为 DynamicProxyGenAssembly2 添加了 InternalsVisibleTo 属性。当我公开课程时,一切正常,但我真的不想公开这些课程。如有任何建议,我将不胜感激。

这是我的上下文类:

internal class LicenseContext : DbContext
{
    public LicenseContext()
    {

    }
    public virtual DbSet<InstalledProduct> ManagedProducts { get; set; }
}

【问题讨论】:

  • 我看不出这与实体框架有什么关系。这完全是 FakeItEasy 的问题,并且使用内部类,这将是您想要伪造的任何其他内部对象的问题。
  • @Yuliam 我很欣赏这种情绪,但请不要混淆我的缩进(我们一直使用白匠风格)。您可能认为您的偏好是一种改进,但您只是假设可以覆盖我的偏好,这有点傲慢。
  • @ErikFunkenbusch 如果您指的是 EntityFramework 标签,那么我将其包括在内,因为我觉得这是其他实体框架用户可能遇到的情况,并且其他人将来可能会遇到。我同意你的看法,但问题不直接出在实体框架上。
  • 嗯,你的问题标题特别提到了DbSet&lt;T&gt;,所以它看起来像是一个 EF 特定的问题。无论如何,您的程序集是否具有强名称?您将InternalsVisibleTo 添加到包含内部类的程序集中,对吗?不是您的测试程序集?
  • @ErikFunkenbusch 嗯,是的,我提到了 DbSet 因为这就是给我带来问题的原因,微软说它应该可以工作。我再次同意你的观点,绝对不是 EF 问题,我的代码总是有问题,但我喜欢尽可能多地提供上下文(请原谅双关语),因为我怀疑我会是唯一一个在尝试模拟 DbSet 时遇到这个问题,在你找到解决方案之前你永远不知道什么是重要的(顺便说一句,我现在有)。

标签: c# entity-framework mocking fakeiteasy


【解决方案1】:

问题解决了!

在我添加 InternalsVisibleTo 属性之前,FakeItEasy 抱怨并告诉我添加这些属性,我很高兴看到它在错误消息中为我提供了我需要的确切代码。我什至对我的一位同事说,“现在就是我所说的错误消息!”。它建议的属性是:

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]

不幸的是,这不起作用,我收到“拒绝访问”错误。可能是公钥不正确,但由于我的程序集不是强命名的,我只是从属性中删除了公钥,一切正常。

最终我将不得不对我的程序集进行强命名,因此我最终必须解决这个公钥问题,但我知道该怎么做,所以它不应该成为障碍。

【讨论】:

  • 我很惊讶/很难过,您收到了错误的错误消息。我们应该检测是否需要在错误消息中包含公钥,因为Issue 157 在 1.14 版中已修复。我可能错过了一个案例,但在我开始撕裂世界之前,您能否确认您使用的是哪个版本的 FakeItEasy?谢谢。
猜你喜欢
  • 2012-06-02
  • 1970-01-01
  • 2012-07-16
  • 1970-01-01
  • 2022-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多