如何在重写的OnModelCreating中单元测试设置的内容

时间:2015-09-28 11:32:12

标签: entity-framework unit-testing

我正在使用Entity Framework 6,在我的上下文中,我已经覆盖了OnModelCreating方法:

protected override void OnModelCreating(DbModelBuilder modelBuilder)

在方法内部,我设置了数据库配置。我想测试一下设置的内容。例如,我有以下代码:

modelBuilder.HasDefaultSchema("public");

我想进行单元测试,检查调用参数值为“public”的HasDefaultSchema。

或者在下面的示例中,我想测试实体UserGroup的HasMany和WithMany方法被调用:

 modelBuilder.Entity<UserGroup>()
             .HasMany<User>(g => g.Users)
             .WithMany(u => u.Groups)
             .Map(ug =>
                  {
                     ug.MapLeftKey("GroupId");
                     ug.MapRightKey("UserId");
                     ug.ToTable("UserGroupMembers");
                  });

请指教。感谢

5 个答案:

答案 0 :(得分:0)

您可以为DbContext创建一个明确调用OnModelCreating的存根,并检查DbModelBuilder的状态

public class TestableMyDbContext : MyDbContext
  {
    public void TestModelCreation(DbModelBuilder model)
    {
        OnModelCreating(model);
        // check your model an throw an exception if invalid
    }
  }

在TestMethod中你捕获异常

[TestMethod]
public void Should_Initialize_Context()
{
  try
  {
    var context = new TestableMyDbContext();
  context.TestCallback(new DbModelBuilder());
  }
  catch (Exception ex)
  {
    Assert.Fail(ex.Message);
  }     
}

答案 1 :(得分:0)

为了建立在vappolinario的答案之上,我使用Mock<DbModelBuilder>并将其传递到TestableDbContext,然后验证模拟被正确调用。

我在我的示例中使用了Moq和xUnit

[Fact]
public void MyContext_HasCorrectDefaultSchema()
{
   var mockModel = new Mock<DbModelBuilder>();
   var context = new TestableMyContext();

   context.TestOnModelCreation(mockModel.Object);

   mockModel.Verify(m => m.HasDefaultSchema("public"), Times.Once());
}

答案 2 :(得分:0)

我在.Net Core中提出了以下解决方案。在我的情况下,我有一个基本的DbContext,在其中解释自定义DataAnnotation以便告诉EF忽略模型类上的某些属性(我想测试的功能)。

我不能简单地使用NotMapped,因为在NotMapped中指定它会导致OData无法看到$select属性,因此我需要一种替代方法来告诉EF忽略,但不会影响OData。

在我的情况下,我还创建了一个TestDbContext,它继承自我的标准测试ModelDbContext类(而该类又继承自我的库DbContextBase类,该类执行EF忽略工作),但是我只是为提供的ModelBuilder设置了一个属性,以便可以在测试期间查询它。

    public class TestDbContext : ModelDbContext
    {
      public ModelBuilder ModelBuilder { get; private set; }

      protected override void OnModelCreating(ModelBuilder modelBuilder)
      {
        base.OnModelCreating(modelBuilder);
        this.ModelBuilder = modelBuilder;
      }
    }

然后我可以使用以下代码对其进行测试:

注意:我必须使用反射来提取所需的EF内部类,以确定是否确实将该字段设置为“忽略”。这通常是不好的做法,但我无法确定确定EF是否忽略这些属性的另一种方法。

    [Fact]
    public void OnModelCreatingTest()
    {
      // Arrange
      DbContextOptionsBuilder<ModelDbContext> builder = new DbContextOptionsBuilder<ModelDbContext>().UseInMemoryDatabase(Guid.NewGuid().ToString());
      var context = new TestDbContext(builder.Options);

      // Act
      // hit the entities to force the model to build
      var testEntity = context.ExampleEntities.FirstOrDefault();
      // use reflection to dig into EF internals
      var builderProperty = typeof(EntityTypeBuilder).GetProperty(
          "Builder",
          System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);

      // Assert
      // validate that the extra ExampleEntity fields are ignored in EF (based on their data annotation)
      context.ModelBuilder.Entity(
        typeof(ExampleEntity),
        b =>
        {
          InternalEntityTypeBuilder baseBuilder = (InternalEntityTypeBuilder)builderProperty.GetValue(b);
          Assert.True(baseBuilder.IsIgnored("Property1", ConfigurationSource.Convention));
          Assert.True(baseBuilder.IsIgnored("Property2", ConfigurationSource.Convention));
        });
    }

答案 3 :(得分:0)

我没有使存根技术起作用,但确实如此:

[TestMethod]
public void Should_Initialize_Context()
{
    try
    {
        var context = new MyDbContextContext("blah");
        context.Database.Initialize(false);

    }
    catch (Exception ex)
    {
        Assert.Fail(ex.Message);
    }
}

答案 4 :(得分:0)

只想提一下,在 EF Core 2.2 中,您可以简单地执行以下操作:

public class MyDbContextTests
{
    [Test]
    public void OnModelCreating_CreateAllModels_AllModelsCreated()
    {
        var context = new MyDbContext();

        Assert.That(() => context.Model, Throws.Nothing);
    }
}

这里,MyDbContext 继承了 DbContext。此测试将调用受保护的 OnConfiguringOnModelCreating 中的 MyDbContext 方法。