Skip to content

Instantly share code, notes, and snippets.

@k30v1n
Last active August 19, 2022 21:48
Show Gist options
  • Save k30v1n/a0a0c1eb65e755f25d68d64dc77defbd to your computer and use it in GitHub Desktop.
Save k30v1n/a0a0c1eb65e755f25d68d64dc77defbd to your computer and use it in GitHub Desktop.
Entity Framework unity testing challenges - mocking DbSet / EntityState
// class `Service`
public void Add()
{
// this is the code I want to test
var entry = await _dbContext.MyDbSetObject.AddAsync(data, cancellationToken);
if (entry.State != EntityState.Added)
{
// log error & return
}
await _dbContext.SaveChangesAsync(cancellationToken);
}
// testing using Moq framework
[Fact]
public void add_should_not_save_changes_with_invalid_entity_state()
{
// Setup
var entity = new MyDbSetObject();
var state = EntityState.Unchanged;
var stateManager = new Mock<IStateManager>();
stateManager
.Setup(manager => manager.CreateEntityFinder(It.IsAny<MyDbSetObject>()))
.Returns(Mock.Of<IEntityFinder>());
// known issue on EF6 / NET6 https://github.com/dotnet/efcore/issues/27110
var internalEntityEntry = new InternalEntityEntry(
stateManager.Object,
new RuntimeEntityType(
name: "T",
type: typeof(T),
sharedClrType: false,
model: null,
baseType: null,
discriminatorProperty: null,
ChangeTrackingStrategy.Snapshot,
indexerPropertyInfo: null,
propertyBag: false),
entity);
var entry = new Mock<EntityEntry<MyDbSetObject>>(internalEntityEntry);
entry.SetupGet(e => e.Entity)
.Returns(entity);
entry.Setup(entityEntry => entityEntry.State)
.Returns(state);
var dbSet = new Mock<DbSet<MyDbSetObject>>();
dbSet
.Setup(dbSet => dbSet.AddAsync(entity, It.IsAny<CancellationToken>()))
.ReturnsAsync(entry.Object);
var builder = new DbContextOptionsBuilder<DatabaseContext>();
var dbContext = new Mock<DatabaseContext>(MockBehavior.Loose, builder.Options);
dbContext
.Setup(context => context.MyDbSetObject)
.Returns(dbSet.Object);
// ACT
var target = new Service(dbContext.Object);
target.Add(entity);
// Assert
dbSet.Verify(moqDbSet => moqDbSet.AddAsync(It.IsAny<MyDbSetObject>(), It.IsAny<CancellationToken>()),
Times.Once);
dbContext.Verify(context => context.SaveChangesAsync(It.IsAny<CancellationToken>()),
Times.Never);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment