【问题标题】:Abstract Generic Mocking - cannot instantiate proxy class of property?Abstract Generic Mocking - 不能实例化属性的代理类?
【发布时间】:2021-03-30 22:18:15
【问题描述】:

我试图在一个抽象泛型类中模拟一个函数,它的构造函数中有更多抽象类。

这是测试:

        [Test]
        public void AbstractRepoTest()
        {
            var options = new Mock<DbContextOptions<CustomDbContext>>();
            var db = new Mock<CustomDbContext>(options);
            var repo = new Mock<BaseRepository<EntityBase>>(db);
            var service = new Mock<BaseService<EntityBase>>(repo, db);

            IQueryable<FactTableRevenue> theInfo = Enumerable.Empty<FactTableRevenue>().AsQueryable();

            repo.Setup(x => x.GetById("test")).Returns(theInfo);

            var abstractService = service.Object;

            Assert.AreEqual(theInfo, abstractService.GetById("test"));
        }

这是 CustomDbContext 构造函数:

 public class CustomDbContext : DbContext
    {
        public CustomDbContext(DbContextOptions<CustomDbContext> options) : base(options)
        {
        }

    }

这是 BaseRepository 构造函数:

public abstract class BaseRepository<T> where T : EntityBase
    {
        internal readonly CustomDbContext _db;

        public BaseRepository(CustomDbContext db)
        {
            _db = db;
        }
     }

这是 BaseService 的构造函数:

  public abstract class BaseService<T> where T : EntityBase
    {
        public DbContext _db { get; }

        public BaseRepository<T> _repository;

        public BaseService(BaseRepository<T> repository, DbContext db)
        {
            _repository = repository;
            _db = db;
        }
    }

这是错误代码:

Tests.UnitTestService.AbstractRepoTest

Castle.DynamicProxy.InvalidProxyConstructorArgumentsException : Can not instantiate proxy of class: Services.Services.BaseService`1[[Database.Common.E...

Castle.DynamicProxy.InvalidProxyConstructorArgumentsException : Can not instantiate proxy of class: Services.Services.BaseService`1[[Database.Common.EntityBase, Database, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].
Could not find a constructor that would match given arguments:
Moq.Mock`1[Services.Repositories.BaseRepository`1[Database.Common.EntityBase]]
Moq.Mock`1[Database.CustomDbContext.CustomDbContext]

   at Castle.DynamicProxy.ProxyGenerator.CreateClassProxyInstance(Type proxyType, List`1 proxyArguments, Type classToProxy, Object[] constructorArguments)
   at Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] interceptors)
   at Moq.CastleProxyFactory.CreateProxy(Type mockType, IInterceptor interceptor, Type[] interfaces, Object[] arguments) in C:\projects\moq4\src\Moq\ProxyFactories\CastleProxyFactory.cs:line 62
   at Moq.Mock`1.InitializeInstance() in C:\projects\moq4\src\Moq\Mock`1.cs:line 311
   at Moq.Mock`1.OnGetObject() in C:\projects\moq4\src\Moq\Mock`1.cs:line 325
   at Moq.Mock.get_Object() in C:\projects\moq4\src\Moq\Mock.cs:line 179
   at Moq.Mock`1.get_Object() in C:\projects\moq4\src\Moq\Mock`1.cs:line 283
   at Tests.UnitTestService.AbstractRepoTest() in C:\Users\USER\RiderProjects\REST\Tests\UnitTestService.cs:line 58

【问题讨论】:

    标签: c# unit-testing mocking moq


    【解决方案1】:

    您遇到的构造问题很可能是您将模拟对象(例如,db)而不是模拟对象(例如,db.Object)传递给模拟构造函数。

    var options = new Mock<DbContextOptions<CustomDbContext>>();
    var db = new Mock<CustomDbContext>(options);
    var repo = new Mock<BaseRepository<EntityBase>>(db.Object);
    var service = new Mock<BaseService<EntityBase>>(repo.Object, db.Object);
    

    【讨论】:

    • 然后我得到这个错误:System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation. ----&gt; System.NullReferenceException : Object reference not set to an instance of an object.
    • 可能还没有在模拟上设置什么?调试它并找出 null 的位置,然后确保它已设置
    • 经过一段时间的调试,它似乎只是疯了,它是一个参考/模拟而不是一个真实的对象。我没有设置,整个测试就是你在这里看到的
    • 您正在存储库上设置GetById("test"),因此这里的代码比重现您遇到的问题所需的代码多。猜测一下,因为您正在模拟实现,所以正在访问一个数据库上下文或存储库成员,但它没有设置。我会考虑模拟接口而不是实现。如果这不可能,请考虑使用内存中的数据库上下文,因为模拟数据库上下文很困难,微软不建议这样做。
    【解决方案2】:

    有两个问题。我在模拟选项并将其提供给我的 DbContext 实现,并且我没有将对象传递给构造函数而不是模拟。

    我通过添加一个空的构造函数更改了 CustomDbContext:

    protected CustomDbContext(){}
    

    并删除了选项并实现了模拟:

                var db = new Mock<CustomDbContext>();
                var repo = new Mock<BaseRepository<EntityBase>>(db.Object);
                var service = new Mock<BaseService<EntityBase>>(repo.Object, db.Object);
    

    【讨论】:

      猜你喜欢
      • 2016-03-31
      • 2021-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多