c# - 处理 DbContext.Entry 时尝试基于 .NET EF Core 对通用存储库进行单元测试失败

标签 c# entity-framework-core repository-pattern unit-of-work

我编写了一个通用存储库(BaseRepository),其中删除方法代码是:

    public virtual void Delete(TEntity entity)
    {
        if (dbContext.Entry(entity).State == EntityState.Detached)
        {
            dbContext.Attach(entity);
        }
        dBContext.Remove(entity);        
    }

我想对代码进行单元测试。由于 DbContext 是外部依赖项,我只想验证当我调用 Repository.Delete(entity) 时,最终 DbContext.Remove(entity) 是被调用一次。但是,我必须在实际 dbContext.Remove(entity) 调用之前模拟 dbContext.Entry 的行为。 单元测试代码为:

    [Fact]
    public void Delete_SomeEntityToRepository_CallsTheAddMethod_To_DbContext()
    {
        // Arrange
        var testObject = new Customer()
        {
            Name = "Test-Customer"
        };
        
        var dbContextMock = new Mock<DbContext>();
        var dbEntityEntryMock = new Mock<EntityEntry<Customer>>();
        
        dbContextMock.Setup(d => d.Entry(testObject)).Returns(dbEntityEntryMock.Object);
        dbEntityEntryMock.Setup(e => e.State).Returns(EntityState.Unchanged);
        
        // Act
        var repository = new CustomerRepository(dbContextMock.Object);
        repository.Delete(testObject);

        //Assert
        dbContextMock.Verify(x => x.Remove(It.Is<Customer>(y => y == testObject)), Times.AtMost(1));
    }

但是这段代码崩溃了,实际上是在以下行: dbContextMock.Setup(d => d.Entry(testObject)).Returns(dbEntityEntryMock.Object); 带有消息: 无法实例化类的代理:Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry`1[[Fx.CommonTests.DataAccess....

系统参数异常 无法实例化类的代理:Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry`1[[Fx.CommonTests.DataAccess.Customer, Fx.CommonTests, Version=4.3.0.0, Culture=neutral, PublicKeyToken=null ]]。 找不到无参数构造函数。 (参数“构造函数参数”)...

显然 DbContext.Entry(...) 是问题所在。那么,关于如何 mock 这个的任何想法???

我尝试了代码的各种变体,如几篇文章中所示,关于如何模拟此类情况,但结果总是相同的。有什么想法吗?

最佳答案

这就是您可以模拟 dbcontext 来防止测试错误的方法,但我相信在设计此测试时可能需要考虑不同的方法(请参阅下面的 but 部分):

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Moq;

// ...
[Fact]
public void Delete_SomeEntityToRepository_CallsTheAddMethod_To_DbContext()
{
    // Arrange
    var testObject = new Customer();

    var internalEntityEntry = GetInternalEntityEntry(testObject);

    var dbEntityEntryMock = new Mock<EntityEntry<Customer>>(internalEntityEntry);
    dbEntityEntryMock.Setup(e => e.State).Returns(EntityState.Unchanged);

    var dbContextMock = new Mock<DbContext>();
    dbContextMock.Setup(d => d.Entry(testObject)).Returns(dbEntityEntryMock.Object);

    // Act
    var repository = new CustomerRepository(dbContextMock.Object);
    repository.Delete(testObject);

    //Assert
    dbContextMock.Verify(x => x.Remove(It.Is<Customer>(y => y == testObject)), Times.AtMost(1));
}

private static InternalEntityEntry GetInternalEntityEntry(Customer testObject)
{
    return new InternalEntityEntry(
        new Mock<IStateManager>().Object,
        new RuntimeEntityType(
            name: nameof(Customer), type: typeof(Customer), sharedClrType: false, model: new(),
            baseType: null, discriminatorProperty: null, changeTrackingStrategy: ChangeTrackingStrategy.Snapshot,
            indexerPropertyInfo: null, propertyBag: false,
            discriminatorValue: null),
        testObject);
}

全文如下:https://gist.github.com/ctrl-alt-d/3d10384a06fa1e0c515e1f182fb83bb0

但是(<- 大“但是”):

关于c# - 处理 DbContext.Entry 时尝试基于 .NET EF Core 对通用存储库进行单元测试失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76450849/

相关文章:

entity-framework-core - 有没有办法让 LinqPad 使用 EF Core 上下文?

c# - Azure Function,EF Core,无法加载 ComponentModel.Annotations 4.2.0.0

dependency-injection - 使用 DbConnection、DbTransaction 与连接池、transactionScope 和依赖注入(inject)的正确方法?

entity-framework - 单个Web应用程序的多个DbContext类。是好是坏?

c# - Entity Framework 提供列名作为字符串变量

c# - 在 Ubuntu 上使用带有 Mono 的 HttpWebResponse 清空响应数据

C# 相当于 file_get_contents (PHP)

c# - Windows Phone 8 在网络浏览器中搜索 bing 时停止打开 bing

c# - 将 Entity Framework Core 的 CosmosDB 提供程序与 Azure 表结合使用时出错

design-patterns - 存储库只是单元测试所必需的吗?