【问题标题】:How do I mock these classes using moq如何使用 moq 模拟这些类
【发布时间】:2014-03-27 23:44:37
【问题描述】:

请有人告诉我如何正确模拟这个存储库类。基本上我只想模拟它,以便我可以轻松地测试我的服务层。 Am moq 在我的测试项目中使用 c# moq。最有问题的地方是 Query、Filter、Include 和 OrderBy 方法中使用的虚拟接口模式。如何模拟它,以便它可以返回我注入到我的存储库模拟中的正确 RepositoryQuery。

下面显示的代码是我与数据库通信的数据库层的一部分,因此我想将其模拟出来,以便我可以轻松地测试我的服务层而无需担心外部依赖。

 public sealed class RepositoryQuery<TEntity> : IRepositoryQuery<TEntity> where TEntity  : BaseEntity
   {

        private readonly List<Expression<Func<TEntity, object>>> _includeProperties;
        private readonly Repository<TEntity> _repository;
        private readonly List<Expression<Func<TEntity, bool>>> _filters;
        private Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> _orderByQuerable;
        private int? _page;
        private int? _pageSize;

        public RepositoryQuery(Repository<TEntity> repository)
        {
            _repository = repository;
            _includeProperties = new List<Expression<Func<TEntity, object>>>();
            _filters = new List<Expression<Func<TEntity, bool>>>();
        }

        public RepositoryQuery<TEntity> Filter(Expression<Func<TEntity, bool>> filter)
        {
            _filters.Add(filter);
            return this;
        }

        public RepositoryQuery<TEntity> OrderBy(Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy)
        {
            _orderByQuerable = orderBy;
            return this;
        }

        public RepositoryQuery<TEntity> Include(Expression<Func<TEntity, object>> expression)
        {
            _includeProperties.Add(expression);
            return this;
        }    

        public IQueryable<TEntity> Get()
        {
            return _repository.Get(_filters, _orderByQuerable, _includeProperties, _page, _pageSize);
        }

    }

还有这个

public class Repository<TEntity> : IRepository<TEntity> where TEntity : BaseEntity
    {
         private readonly Guid _instanceId;
        private readonly DbSet<TEntity> _dbSet;
        private readonly IDbContext _context; 

        public Repository(IDbContext context)
        {
            _context = context;
            _dbSet = context.Set<TEntity>();
            _instanceId = Guid.NewGuid();
        }

        public virtual IRepositoryQuery<TEntity> Query()
        {
            var repositoryGetFluentHelper = new RepositoryQuery<TEntity>(this);
            return repositoryGetFluentHelper;
        }

        internal IQueryable<TEntity> Get(
            List<Expression<Func<TEntity, bool>>> filters = null,
            Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
            List<Expression<Func<TEntity, object>>> includeProperties = null,
            int? page = null,
            int? pageSize = null)
        {
            IQueryable<TEntity> query = _dbSet;

            if (includeProperties != null)
            {
                includeProperties.ForEach(i => query = query.Include(i));
            }

            if (filters != null && filters.Any())
            {
                query = filters.Aggregate(query, (current, filter) => current.Where(filter));
            }

            query = orderBy != null ? orderBy(query) : query.OrderBy(a => a.Id);

            if (page != null && pageSize != null)
            {
                query = query
                    .Skip((page.Value - 1)*pageSize.Value)
                    .Take(pageSize.Value);
            }
            return query;
        }


    }

【问题讨论】:

  • 您模拟的内容完全取决于您当前正在运行的测试。我们无法为您提供帮助。这完全取决于您。查找基本的模拟教程,以了解人们为每个测试模拟了什么。例如:您不会为了测试一个功能而模拟整个存储库。
  • 嗨,上面的一些代码是我在数据层中使用的,因为它与数据存储通信,我想完全模拟它,这样我不仅可以测试一个函数,而且可以测试我的整个服务层。

标签: c# unit-testing moq


【解决方案1】:

希望您的组件依赖于接口IRepositoryQuery&lt;TEntity&gt;IRepository&lt;TEntity&gt;,而不是具体的实现RepositoryQuery&lt;TEntity&gt;Repository&lt;TEntity&gt;。如果是这种情况,那么您可以为接口提供测试替身,以便像这样使用 Moq 进行单元测试

var mockQuery = new Mock<IRepositoryQuery<TEntity>>();

// perform any setup needed on mockQuery for the particular System Under Test

var mockRepository = new Mock<IRepository<TEntity>>();

// perform any setup needed on mockRepository for the particular System Under Test

// component that relies on query and repository
// that is the System Under Test i.e. the focus of the unit test
var systemUnderTest = new SystemUnderTest(mockRepository.Object, mockQuery.Object);

观察;查看RepositoryQuery&lt;TEntity&gt;,我认为方法应该返回接口IRepositoryQuery&lt;TEntity&gt;,而不是具体实现RepositoryQuery&lt;TEntity&gt;

【讨论】:

  • 两者都有接口,但RepositoryQuery&lt;TEntity&gt;Repository&lt;TEntity&gt; 紧密耦合,因为它充当存储库类的帮助器,这让我感到困惑。
  • @Cizaphil 那么界面是什么样的?
【解决方案2】:

如果IRepositoryQueryIRepository 的包装器,那么——为了测试你的服务层——你不需要模拟IRepository。只是模拟IRepositoryQuery

假设我想检查SomeService.DoSomething 是否正确处理了它从IRepositoryQuery.Get 获得的结果:

var mock = new Mock<IRepositoryQuery<SomeClass>>();
mock.Setup(o => o.Get(/* test parameters */)).Returns(/* result */);

var myService = new SomeService(mock.Object);
Assert.That(myService.DoSomething(), Is.EqualTo(/* expected result*/));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-11
    • 2015-04-04
    • 1970-01-01
    • 1970-01-01
    • 2019-01-08
    • 2018-03-29
    • 2012-06-16
    • 1970-01-01
    相关资源
    最近更新 更多