Moq с IQueryable методами расширения
Я новичок в Moq Framework и модульном тестировании в целом, я пытаюсь создать модульный тест для своей функции репозитория ниже.
Метод репозитория
public IQueryable<Campaign> AllIncluding(params Expression<Func<Campaign, object>>[] includeProperties)
{
IQueryable<Campaign> query = _context.Campaigns;
foreach (var includeProperty in includeProperties)
{
query = query.Include(includeProperty);
}
return query;
}
Модульный тест с настройкой Moq
//Arrange
var data = new List<Models.Campaign>
{
new Models.Campaign { Id = 1, Name = "Campaign Past", StartDate = DateTime.Now.AddDays(-10), EndDate = DateTime.Now.AddDays(-5) },
new Models.Campaign { Id = 2, Name = "Campaign Active", StartDate = DateTime.Now.AddDays(-4), EndDate = DateTime.Now.AddDays(3) },
new Models.Campaign { Id = 2, Name = "Campaign Future", StartDate = DateTime.Now.AddDays(4), EndDate = DateTime.Now.AddDays(10) }
}.AsQueryable();
var _moqSet = new Mock<DbSet<Models.Campaign>>();
_moqSet.As<IQueryable<Models.Campaign>>().Setup(m => m.Provider).Returns(data.Provider);
_moqSet.As<IQueryable<Models.Campaign>>().Setup(m => m.Expression).Returns(data.Expression);
_moqSet.As<IQueryable<Models.Campaign>>().Setup(m => m.ElementType).Returns(data.ElementType);
_moqSet.As<IQueryable<Models.Campaign>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
//_moqSet.As<IQueryable<Models.Campaign>>()
// .Setup(m => m.Include(It.IsAny<Expression<Func<Models.Campaign, object>>>()))
// .Returns((Expression<Func<Models.Campaign, object>> predicate) =>
// {
// return _moqSet.Object.Include(predicate);
// });
var _moqContext = new Mock<Context.IPrizeSelectionContext>();
_moqContext.Setup(m => m.Campaigns).Returns(_moqSet.Object);
Func<IQueryable<Models.Campaign>, Expression<Func<Models.Campaign, object>>, IQueryable<Models.Campaign>> includeMethod = (query, expression) =>
{
return query.Include(expression);
};
//Act
List<Models.Campaign> allResults = null;
using (var sut = new CampaignRepository(_moqContext.Object, includeMethod))
{
allResults = sut.AllIncluding(o => o.Id, o => o.Name).OrderBy(o => o.Id).ToList();
}
//Assert
Assert.IsNotNull(allResults);
Assert.AreEqual(3, allResults.Count);
Assert.IsNull(allResults[0].StartDate);
Я получаю нулевые данные после query.include(includeProperty)
Я пытался издеваться над функцией включения, но я получаю Expression references a method that does not belong to the mocked object: m => m.Include<Campaign,Object>(It.IsAny<Expression'1>())
исключение при попытке установить Mock DbSet. После некоторых копаний я обнаружил, что Moq имеет проблемы или не может смоделировать методы расширения, см. Методы исключения вопроса Mocking с Moq
Следуя инструкциям в этом блоге, я попытался выполнить шаблон делегата.
Репозиторий Переписать
Func<IQueryable<Campaign>, Expression<Func<Campaign, object>>, IQueryable<Campaign>> _includeMethod = null;
...
public CampaignRepository(IPrizeSelectionContext context, Func<IQueryable<Campaign>, Expression<Func<Campaign, object>>, IQueryable<Campaign>> includeMethod)
: this(context)
{
_includeMethod = includeMethod;
}
...
public IQueryable<Campaign> AllIncluding(params Expression<Func<Campaign, object>>[] includeProperties)
{
IQueryable<Campaign> query = _context.Campaigns;
foreach (var includeProperty in includeProperties)
{
if (_includeMethod == null)
query = query.Include(includeProperty);
else
query = _includeMethod(query, includeProperty);
}
return query;
}
Вот мои настройки модульного теста
Func<IQueryable<Models.Campaign>, Expression<Func<Models.Campaign, object>>, IQueryable<Models.Campaign>> includeMethod = (query, expression) =>
{
return query.Include(expression);
};
List<Models.Campaign> allResults = null;
using (var sut = new CampaignRepository(_moqContext.Object, includeMethod))
{
allResults = sut.AllIncluding(o => o.Id, o => o.Name).OrderBy(o => o.Id).ToList();
}
Однако этот шаблон также заканчивается так же, IQueryable<Campaign> query = _context.Campaigns;
возвращает тип Mock, но я не могу использовать метод расширения.
Кто-нибудь может указать мне правильное направление, чтобы проверить мой метод хранилища?
1 ответ
Похоже, вы пытаетесь проверить 2 вещи здесь: 1. Включить метод расширения 2. Метод AllInc ключение
Я предлагаю вам разделить метод Include на другой статический класс, такой как:
public static class CollectionExtensions {
public static Include(this IQueryable<Campaign>, Expression<Func<Campaign, object>> includeProperty) {
// put implementation here
}}
Таким образом, вы можете протестировать метод Include отдельно. (Большая часть логики, похоже, внутри метода include)
Также я не думаю, что вы можете использовать _moqSet.Object внутри настройки _moqSet, как показано ниже. Вероятно, это и является причиной того, что moq не может разрешить выражение.
_moqSet.As<IQueryable<Models.Campaign>>()
.Setup(m => m.Include(It.IsAny<Expression<Func<Models.Campaign, object>>>()))
.Returns((Expression<Func<Models.Campaign, object>> predicate) =>
{
return _moqSet.Object.Include(predicate);
});