我正在使用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");
});
请指教。感谢
答案 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
。此测试将调用受保护的 OnConfiguring
和 OnModelCreating
中的 MyDbContext
方法。