I'm using Entity Framework 6 and in my context I have overridden OnModelCreating method:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
Inside the method, I set up the database configuration. I would like to test what is set up. For instance, I have the following code:
modelBuilder.HasDefaultSchema("public");
I would like to have a unit test which checks that HasDefaultSchema with parameter value "public" is called.
Or like in the following example I would like to test that HasMany and WithMany methods of entity UserGroup are called:
modelBuilder.Entity<UserGroup>()
.HasMany<User>(g => g.Users)
.WithMany(u => u.Groups)
.Map(ug =>
{
ug.MapLeftKey("GroupId");
ug.MapRightKey("UserId");
ug.ToTable("UserGroupMembers");
});
Please advise. Thanks
I came up with the following solution in .Net Core. In my case I have a base DbContext where I interpret a custom DataAnnotation in order to tell EF to ignore certain properties on my model classes (the functionality I wanted to test).
I could not simply use NotMapped
because it caused OData to not be able to see NotMapped
properties when specified in the $select
, so I needed an alternative way to tell EF to ignore, but not impact OData.
In my case I also created a TestDbContext
which inherited from my standard test ModelDbContext
class (which in turn inherits from my library DbContextBase
class which does the EF Ignore work), but I simply set a property to the provided ModelBuilder
so that I could interrogate it during my tests.
public class TestDbContext : ModelDbContext
{
public ModelBuilder ModelBuilder { get; private set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
this.ModelBuilder = modelBuilder;
}
}
Then I could test it using the following code:
Note: I had to use reflection to extract the EF internal classes required to determine if indeed the field was set to Ignored. This is normally bad practice, but I could not figure out another way of determining whether EF was ignoring these properties.
[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));
});
}
To build on vappolinario's answer, I used a Mock<DbModelBuilder>
and passed that into the TestableDbContext
, and then verified that the mock was called correctly.
I am using Moq and xUnit in my example
[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());
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With