MOQ Setup使用构造函数参数获取dbContext

如何解决MOQ Setup使用构造函数参数获取dbContext

情况

在这里尝试通过MOQ为GroupService编写一些单元测试。

要创建我的GroupService的实例,我模拟了4个需要通过构造函数传递的接口。现在在其中一个模拟(IGroupRepository上,调用一个名为Context属性,我的想法是将SetupGet设置为该属性,并仅返回虚假的GroupUser列表。但无论尝试如何,我都会不断出错。

代码

public class GroupServiceTests
{
    private readonly GroupService _groupService;
    private readonly Mock<AppDbContext> _dbContext;
    private readonly Mock<IGroupRepository> _groupRepository;
    private readonly Mock<IComponentService> _componentService;
    private readonly Mock<IUserContextService> _userContextService;
    private readonly Mock<IModelEntityMapper<Group,Core.DbContexts.Entities.Group>> _mapper;

    public GroupServiceTests()
    {
        var groupUsersMock = CreateDbSetMock(GetFakelistofGroupUsers());
        _dbContext = new Mock<AppDbContext>(new DbContextOptions<AppDbContext>());
        _dbContext.SetupGet(x => x.GroupUser).Returns(groupUsersMock.Object);

        _groupRepository = new Mock<IGroupRepository>();
        _groupRepository.SetupGet(repo => repo.Context).Returns(_dbContext.Object);

        _componentService = new Mock<IComponentService>();
        _userContextService = new Mock<IUserContextService>();
        _mapper = new Mock<IModelEntityMapper<Group,Core.DbContexts.Entities.Group>>();

        _groupService = new GroupService(_groupRepository.Object,_componentService.Object,_userContextService.Object,_mapper.Object);
    }
}

GroupService中,此行称为:

// _repository reffers to IGroupRepository
userIdsForContextReset.AddRange(_repository.Context.GroupUser.Where(x => groupIds.Contains(x.GroupId)).Select(x => x.UserId));

GroupRepositoryEntityRepository看起来像这样:

public interface IGroupRepository : IEntityRepository<AppDbContext,Group>
{
    List<GroupPermission> GetInheritedGroupPermissions(int groupId);
}

public class GroupRepository : EntityRepository<AppDbContext,Group>,IGroupRepository
{
    public GroupRepository(AppDbContext dbContext) : base(dbContext)
    {
    }

    public List<GroupPermission> GetInheritedGroupPermissions(int groupId)
    {
        // Removed for brevity
    }
}
public class EntityRepository<TDbContext,TEntity> : EntityRepository<TDbContext,TEntity,int>,IEntityRepository<TDbContext,TEntity>
     where TDbContext : DbContext
     where TEntity : class,IEntity<int>
{
    public EntityRepository(TDbContext dbContext) : base(dbContext)
    {
    }
}
public class EntityRepository<TDbContext,TId> : IEntityRepository<TDbContext,TId>
     where TDbContext : DbContext
     where TEntity : class,IEntity<TId>
     where TId : IComparable
{
    public EntityRepository(TDbContext context)
    {
        Context = context;
    }

    public TDbContext Context { get; }
}

最后但同样重要的是AppDbContextsqlDbContext

public class AppDbContext : Shared.DbContexts.sqlDbContext
{
    public virtual DbSet<GroupUser> GroupUser { get; set; }

    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
    {
    }
}
public class sqlDbContext : DbContext
{
    public sqlDbContext(DbContextOptions options) : base(options)
    {
        ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
        ChangeTracker.StateChanged += ChangeTracker_StateChanged;
    }
}

错误

我得到的错误是在构造函数内部第一行的sqlDbContext内部,并显示以下内容

system.invalidOperationException:'尚未为此DbContext配置数据库提供程序。可以通过重写DbContext.OnConfiguring方法或在应用程序服务提供程序上使用AddDbContext来配置提供程序。如果使用AddDbContext,则还请确保您的DbContext类型在其构造函数中接受DbContextOptions对象,并将其传递给DbContext的基本构造函数。'

我在做什么错了?

解决方法

模拟实现时,它使用与提供的参数匹配的构造函数创建对象;它运行该代码。 此外,所有无法嘲笑的东西(不是虚拟的或抽象的)都将照常运行。在这种情况下,您要传递DbContextOptions,而您尚未指定提供程序,而某些操作则需要该提供程序。

这可能是一个自以为是的话题,但是要解决您的问题,有多种方法可以解决:

  1. 将无参数构造函数添加到DbContext中进行测试。我不建议您这样做,因为我遵循不更改测试的SUT的口号。
  2. 使用内存提供程序; EF Core In-Memory Database ProviderSQLite EF Core Database Provider是我使用的两个。它们确实有局限性,但使用OP可能会很好,并解决了Microsoft关于您不应该mock the DbContext的注意事项。
  3. 使用现有的库,例如EntityFrameworkCore.Testing(免责声明,我是作者),该库将扩展内存提供程序以解决其局限性。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?