这是我要测试的方法:
public async Task<List<Lesson>> GetProfessionalLessonsByTutorIdAsync(long tutorId)
{
return await _unitOfWork.Repository<Lesson>().GetEntities(l => l.TeacherId == tutorId && l.LessonTypeId == 1)
.AsNoTracking().ToListAsync();
}
这里的GetEntities
方法如下:
public IQueryable<TEntity> GetEntities(Expression<Func<TEntity, bool>> condition = null,
Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>> include = null)
{
IQueryable<TEntity> query = _dbSet;
if (condition != null)
{
query = query.Where(condition);
}
if (include != null)
{
query = include(query);
}
return query;
}
我的测试方法:
[Fact]
public async Task GetProfessionalLessonsByTutorIdAsync_WithTutorIdInputParam_ReturnsListOfLesson()
{
// Arrange
private readonly Mock<IUnitOfWork> _mockUnitOfWork = new Mock<IUnitOfWork>();
private readonly Mock<IHttpContextAccessor> _mockContextAccessor = new Mock<IHttpContextAccessor>();
private readonly Mock<IUserService> _mockUserService = new Mock<IUserService>();
var fakeLessonList = new List<Lesson>
{
new Lesson() { LessonId = 1, LessonTypeId = 1,LanguageId = 1, TeacherId = 1, LessonName = "Professional Lesson"},
new Lesson() { LessonId = 2,LessonTypeId = 2, LanguageId = 2, TeacherId = 2, LessonName = "Professional Lesson"}
}.AsQueryable().BuildMock();
_mockUnitOfWork.Setup(uow => uow.Repository<Lesson>().GetEntities(It.IsAny<Expression<Func<Lesson, bool>>>() ,
It.IsAny<Func<IQueryable<Lesson>, IIncludableQueryable<Lesson, object>>>())).Returns(fakeLessonList.Object);
LessonService lessonService = new LessonService(_mockUnitOfWork.Object, _mockContextAccessor.Object, _mockUserService.Object);
// Act
var exceptedValue = 1;
List<Lesson> lessons = await lessonService .GetProfessionalLessonsByTutorIdAsync(1);
var actualValue = lessons.Count; // Here count should be 1 but its getting 2
//Assert
Assert.Equal(exceptedValue, actualValue);
}
问题是当在测试方法中调用await lessonService.GetProfessionalLessonsByTutorIdAsync(1);
时,它返回2个项目,实际上它应该返回匹配条件的1个。
我猜问题出在以下模拟设置代码中:
_mockUnitOfWork.Setup(uow => uow.Repository<Lesson>().GetEntities(It.IsAny<Expression<Func<Lesson, bool>>>() ,
It.IsAny<Func<IQueryable<Lesson>, IIncludableQueryable<Lesson, object>>>())).Returns(fakeLessonList.Object);
我可能错过了一些东西!请专家提供任何帮助!
注意:如果我按如下方式修改原始方法,那么它将起作用。
public async Task<List<Lesson>> GetProfessionalLessonsByTutorIdAsync(long tutorId)
{
return await _unitOfWork.Repository<Lesson>().GetEntities().Where(l => l.TeacherId == tutorId && l.LessonTypeId == 1)
.AsNoTracking().ToListAsync();
}
现在另一个问题是,为什么测试方法适用于GetEntities().Where(l => l.TeacherId == tutorId && l.LessonTypeId == 1)
而不适用于.GetEntities(l => l.TeacherId == tutorId && l.LessonTypeId == 1)
。
答案 0 :(得分:1)
设置的问题是您将GetEntities
设置为始终返回完整的fakeLessonList
列表。您永远不会遇到作为参数提供的查询。
为此,您可以使用Moq Returns()
方法的另一个重载,该方法提供调用方通过lambda方法传递的参数。另外,如果您要在给定条件下实际过滤掉,也就不必模拟列表,也就是说,真正运行查询。
var fakeLessonList = new List<Lesson>
{
new Lesson() { LessonId = 1, LessonTypeId = 1,LanguageId = 1, TeacherId = 1, LessonName = "Professional Lesson"},
new Lesson() { LessonId = 2,LessonTypeId = 2, LanguageId = 2, TeacherId = 2, LessonName = "Professional Lesson"}
}.AsQueryable(); // .BuildMock(); - no mock, just a real list
_mockUnitOfWork.Setup(uow => uow.Repository<Lesson>().GetEntities(It.IsAny<Expression<Func<Lesson, bool>>>(),
It.IsAny<Func<IQueryable<Lesson>, IIncludableQueryable<Lesson, object>>>()))
.Returns(
(Expression<Func<Lesson, bool>> condition,
Func<IQueryable<Lesson>, IIncludableQueryable<Lesson, object>> include) =>
// Run the queries against the list
// Need to add some checks in case any of those are null
fakeLessonList.Where(condition)
);
我没有测试代码,但我希望它能为您提供需要调整的想法。
编辑: 这就是您的测试中发生的事情。
GetEntities()
的模拟以及其他一些... await lessonService .GetProfessionalLessonsByTutorIdAsync(1);
方法。GetEntities(condition)
的 mock ,但是它只是忽略了condition
,因为您的 mock (进行设置)不会评估任何条件,它始终会返回完整列表。换句话说,您的GetProfessionalLessonsByTutorIdAsync
方法调用GetEntities(condition)
还是GetEntities()
根本没有区别,因为模拟已设置为始终返回完整列表并忽略传递给它的任何条件。
如果将GetProfessionalLessonsByTutorIdAsync
的代码更改为运行GetEntities().Where(condition)
,则最终将根据condition
返回的列表评估GetEntities()
。这样做的问题是您不再控制condition
发生了什么。