【问题标题】:Is there a way I can mock _currencyRepository in this line of code?有没有办法可以在这行代码中模拟 _currencyRepository?
【发布时间】:2020-01-15 08:50:26
【问题描述】:

我正在尝试使用 MOQ 框架对一个类进行单元测试。类中的公共方法有如下一行。

看着那条线,我试图模拟 _currencyRepository 但不知道该怎么做。考虑到它有一个像p => new { p.Id, p.Code } 这样的参数。

在分析代码时,它似乎是一种输出 P 的方式 - 我相信匿名方法。

var currencies = await _currencyRepository.GetsAs(p => new { p.Id, p.Code }, p => p.Id == sellCurrencyId || p.Id == buyCurrencyId);

将鼠标悬停在 var 上以了解获取返回的类型,提示显示 IEnumerable<'a> currencies. Anonymous types: 'a is new{Guid Id, string code}

..而 GetAs 的定义是:

public async Task<IEnumerable<TOutput>> GetsAs<TOutput>(Expression<Func<TEntity, TOutput>> projector,
                                               Expression<Func<TEntity, bool>> spec = null,
                                               Func<IQueryable<TEntity>, IQueryable<TEntity>> preFilter = null,
                                               params Func<IQueryable<TEntity>, IQueryable<TEntity>>[] postFilters)
        {
            if (projector == null)
            {
                throw new ArgumentNullException("projector");
            }

            return await FindCore(true, spec, preFilter, postFilters).Select(projector).ToListAsync();
        }

GetAs() 也是通用类 GenericRepository 中的成员/方法 - 其类定义为:

    public class GenericRepository<TContext, TEntity> : IGenericRepository<TEntity>
        where TEntity : BaseEntity
        where TContext : DbContext
    {
        protected readonly TContext DbContext;
        public GenericRepository(TContext dbContext)
        {
            DbContext = dbContext;
        }

      //followed by method definitions including GetAs
}

上面的类继承自泛型接口IGenericRepository&lt;TEntity&gt;,定义为:

    public interface IGenericRepository<TEntity>
        where TEntity : class
    {
        //list of methods including GetAs
         Task<IEnumerable<TOutput>> GetsAs<TOutput>(Expression<Func<TEntity, TOutput>> projector,
            Expression<Func<TEntity, bool>> spec = null,
            Func<IQueryable<TEntity>, IQueryable<TEntity>> preFilter = null,
            params Func<IQueryable<TEntity>, IQueryable<TEntity>>[] postFilters);

...BaseEntity 只是一个具有属性的类:

    public class BaseEntity
    {
        public BaseEntity()
        {
            Id = Guid.NewGuid();
            CreatedDate = DateTime.Now;
        }
        public Guid Id { get; set; }
        public DateTime CreatedDate { get; set; }
        public DateTime? UpdatedDate { get; set; }
        public Guid? CreatedBy { get; set; }
        public Guid? UpdateddBy { get; set; }

    }

我已经有了要返回的货币列表,只是参数有错误。不确定要使用什么参数匹配器(我知道参数匹配器是 NSubstitute 谈话。不确定在起订量中它是否被称为相同)

我尝试了很多东西。其中之一如下:

            var mockCurrencies3 = new[] { new { Id = buyCurrencyId, Code = "EUR" }, new { Id = sellCurrencyId, Code = "GBP" } };
            MockCurrencyRepository.Setup(x => x.GetsAs(
               It.IsAny<Expression<Func<Currency, (Guid, string)>>>(),
               It.IsAny<Expression<Func<Currency, bool>>>(),
               It.IsAny<Func<IQueryable<Currency>, IQueryable<Currency>>>()))
               .Returns(Task.FromResult(mockCurrencies3.AsEnumerable()));

尝试上述方法不起作用,因为mockCurrencies3 值未在生产代码中返回。我没有得到任何回报。

【问题讨论】:

  • 显示您要模拟的成员的定义。
  • 抱歉,忘记补充了。我刚刚添加了 GetAs() 的定义,它是一个 Async 方法。
  • TEntity 来自哪里?
  • @Nkosi:因此,GetAs 是 GenericRepository 类中的成员/方法,它是通用的,而 TEntity 是基础类型之一。这是类声明:``` public class GenericRepository : IGenericRepository where TEntity : BaseEntity where TContext : DbContext
  • 这应该包含在问题中。如果我们要能够重现问题,我们需要了解整个情况。这个成员是泛型接口的一部分还是只是泛型类?

标签: c# unit-testing moq


【解决方案1】:

使用提供的信息,我能够创建一个通用方法来设置所需的行为

[TestClass]
public class MyTestClass {
    [TestMethod]
    public async Task  Should_Mock_Generic() {

        Guid buyCurrencyId = Guid.NewGuid();
        Guid sellCurrencyId = Guid.NewGuid();

        var mockCurrencies3 = new[] { new { Id = buyCurrencyId, Code = "EUR" }, new { Id = sellCurrencyId, Code = "GBP" } };

        var mock = new Mock<IGenericRepository<Currency>>();
        SetupGetAs(mock, mockCurrencies3);

        var _currencyRepository = mock.Object;

        var currencies = await _currencyRepository.GetsAs(p => new { p.Id, p.Code }, p => p.Id == sellCurrencyId || p.Id == buyCurrencyId);

        currencies.Should().NotBeNullOrEmpty();
    }

    Mock<IGenericRepository<TEntity>> SetupGetAs<TEntity, TOutput>(Mock<IGenericRepository<TEntity>> mock, IEnumerable<TOutput> source)
        where TEntity : class {
        mock.Setup(x => x.GetsAs(
          It.IsAny<Expression<Func<TEntity, TOutput>>>(),
          It.IsAny<Expression<Func<TEntity, bool>>>(),
          It.IsAny<Func<IQueryable<TEntity>, IQueryable<TEntity>>>())
       )
       .ReturnsAsync(source);

        return mock;
    }

}

【讨论】:

  • 非常感谢。我必须阅读一些内容才能使用您的解决方案。
猜你喜欢
  • 2020-09-15
  • 2016-12-11
  • 1970-01-01
  • 2015-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-06
  • 1970-01-01
相关资源
最近更新 更多