【问题标题】:Mocking using MOQ and generic types使用 MOQ 和泛型类型进行模拟
【发布时间】:2014-09-22 23:43:24
【问题描述】:

单元测试方法:GetUserInfo

以下是包含该方法的类:

public class AccountService : IAccountService
{
    IUnitOfWork _UnitOfWork;

    public AccountService(IUnitOfWork unitOfWork)
    {
        _UnitOfWork = unitOfWork;
    }

    public UserInfo GetUserInfo(string userName, string password)
    {
        var userInfo = new UserInfo();
        userInfo.UserType = UserType.Invalid;

   // Statement of interest
   var portalUser = _UnitOfWork.Repository<DvaPortalUser>().Query().Filter(t => t.Email == userName && t.Password == password).Get().FirstOrDefault();

        //....Rest of the code is not included for clarity
    }
}

模拟 IUnitOfWork 的接口:

public interface IUnitOfWork
{
    void Dispose();
    void Save();
    void Dispose(bool disposing);
    IRepository<T> Repository<T>() where T : class;
}

存储库实现:

public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{

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

        return repositoryGetFluentHelper;
    }

  internal IEnumerable<TEntity> Get(
        Expression<Func<TEntity, bool>> filter = 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.Include(i));

        if (filter != null)
            query = query.Where(filter);

        if (orderBy != null)
            query = orderBy(query);

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


        return query.ToList();
    }
}

RepositoryQuery 实现:

public sealed class RepositoryQuery<TEntity> where TEntity : class
{
    private readonly List<Expression<Func<TEntity, object>>> _includeProperties;

    private readonly Repository<TEntity> _repository;
    private Expression<Func<TEntity, bool>> _filter;
    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>>>();
    }

    public RepositoryQuery<TEntity> Filter(Expression<Func<TEntity, bool>> filter)
    {
        _filter = filter;
        return this;
    }


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

单元测试方法:

 [TestMethod]
 public void AccountService_GetUserInfo_SuccessfulLogin()
 {
    var  _UnitOfWork = new Mock<IUnitOfWork>();
    _AccountService = new AccountService(_UnitOfWork.Object);

    _UnitOfWork.Setup(a =>  a.Repository<T>())).Returns(??); //How do I setup this statement?
    _UnitOfWork.VerifyAll();
 }

问题:如何为语句 _UnitOfWork.Repository() 设置模拟调用?

【问题讨论】:

    标签: c# unit-testing moq


    【解决方案1】:

    我不知道你的IRepository&lt;T&gt; 是如何实现的,但我猜你的Query 方法返回一个IEnumerable&lt;T&gt; 或一个列表。

    internal interface IRepository<T>
    {
        IEnumerable<T> Query();
    }
    
    // your mock
    _UnitOfWork.Setup(a =>  a.Repository<DvaPortalUser>())).Returns(() => new MyTestRepository());
    

    1。解决方案

    定义存储库的显式实现。

    // your implementation
    public class MyTestRepository : IRepository<DvaPortalUser>
    {
        public IEnumerable<DvaPortalUser> Query()
        {
           // return some test users (mocks)
           return new List<DvaPortalUser> {new DvaPortalUser(), new DvaPortalUser()};
        }
    }
    

    2。解决方案(感谢 Yuliam Chandra)

    定义一个模拟而不是实现

    var repository = new Mock<IRepository<DvaPortalUser>>(); 
    // return some test users (mocks)
    repository.Setup(a => a.Query()).Returns(new[] { new DvaPortalUser() });
    _UnitOfWork.Setup(a =>  a.Repository<DvaPortalUser>()).Returns(repository.Object);
    

    您选择什么取决于您的解决方案。

    【讨论】:

    • 为什么不为存储库创建一个模拟而不是存根?
    • 因为你的 mock 需要知道要处理的类型。我猜泛型 不能使用。
    • 类似var rep = new Mock&lt;IRepository&lt;DvaPortalUser&gt;&gt;(); 然后rep.Setup(a =&gt; a.Query()).Returns(new[] { new DvaPortalUser() }); 然后是_UnitOfWork.Setup(a =&gt; a.Repository&lt;DvaPortalUser&gt;())).Returns(rep.Object); 免责声明:浏览器中的代码,尚未测试
    • 啊好的,现在我明白你的评论了。对,那是另一种方式。我会将其添加到答案中。谢谢!
    猜你喜欢
    • 2012-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-13
    • 2016-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多