如何模拟 dbSet.AddAsync(obj).Entity

How to mock dbSet.AddAsync(obj).Entity

我有一个带有单元和集成测试的项目。不幸的是,由于某些原因我无法使用任何集成测试,所以我不得不使用单元测试。

我的项目中有下面的代码。

var associationEntity = (await _context.UsersAssociations.AddAsync(association)).Entity;
await _context.Entry(associationEntity.Guest).Collection(g => g.Accounts).LoadAsync();

_context 是一个 Entity Framework DbContext。我正在使用 AddAsync 以获得更好的性能,所以我不能使用 .Add(association) 方法。

我正在使用带有 Moq 的模拟并且正在模拟 DbContext。

我的 objective 是为我的单元测试获取 .Entity 对象。不幸的是,我所有的尝试和互联网提供的东西都无法让它发挥作用。 await _context.UsersAssociations.AddAsync(association) 总是返回 null 而不是它应该返回的 EntityEntry。

这是我最近的尝试:

var dbContextMock = UnitTestHelper.GetDbContextMock();
var usersAssociationsSetMock = UnitTestHelper.GetDbSetMock(new List<UsersAssociation>());

var usersAssociationEntryMock = new Mock<EntityEntry<UsersAssociation>>();
usersAssociationEntryMock.Setup(x => x.Entity)
    .Returns(userAssociationMock); // It should returns an object defined before this part.

usersAssociationsSetMock.Setup(x => x.AddAsync(It.IsAny<UsersAssociation>(), It.IsAny<CancellationToken>()))
    .Returns((UsersAssociation model, CancellationToken token) => new ValueTask<EntityEntry<UsersAssociation>>(usersAssociationEntryMock.Object));

我在想 entryMock.Entity 可以给我 usersAssociationMock。但是,usersAssociationEntryMock.Object 不起作用。出现错误:“找不到无参数构造函数”。

下面是我尝试过的方法以及未成功的原因:

如果您有任何想法或需要更多代码,请不要犹豫 :) 我在 dbSet.AddAsync() 模拟方面发现的帮助很少,所以在我想要的方面的帮助就更少了。

提前谢谢你,祝你今天愉快,即使你没有帮助我:D

答案是我们做不到。我们不能模拟 EntityEntry 对象,也不应该这样做。 这是来源:https://github.com/dotnet/ef6/issues/208

相反,内存数据库应该用于数据库事务的单元测试。

(还没试过)

在 EF 6.0 中你可以使用这个:

var dbSetMock = new Mock<DbSet<FakeEntity>>();
dbSetMock.Setup(_ => _.AddAsync(It.IsAny<FakeEntity>(),
    It.IsAny<CancellationToken>()))
    .Returns<FakeEntity, CancellationToken>((e, c) =>
    {
        var stateManagerMock = new Mock<IStateManager>();
        var entityTypeMock = new Mock<IRuntimeEntityType>();
        entityTypeMock
            .SetupGet(_ => _.EmptyShadowValuesFactory)
            .Returns(() => new Mock<ISnapshot>().Object);
        entityTypeMock
            .SetupGet(_ => _.Counts)
            .Returns(new PropertyCounts(1, 1, 1, 1, 1, 1));
        entityTypeMock
            .Setup(_ => _.GetProperties())
            .Returns(Enumerable.Empty<IProperty>());
        var internalEntity = new InternalEntityEntry(stateManagerMock.Object,
            entityTypeMock.Object, e);
        var entry = new EntityEntry<FakeEntity>(internalEntity);
        return ValueTask.FromResult(entry);
    });