выражение> не работает должным образом в макете установки - PullRequest
0 голосов
/ 27 декабря 2018

Это метод, который я хочу проверить:

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).

1 Ответ

0 голосов
/ 27 декабря 2018

Проблема с вашей настройкой заключается в том, что вы устанавливаете GetEntities, чтобы всегда возвращать полный список fakeLessonList.Вы никогда не сталкиваетесь с запросами, представленными в качестве аргументов.

Для этого вы можете использовать другую перегрузку метода Moq Returns(), которая предоставляет аргументы, переданные вызывающей стороной через лямбда-метод.Кроме того, нет необходимости смоделировать список, если вы действительно хотите отфильтровать с заданными условиями, то есть выполнить запросы на реальные.

    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) но он просто игнорирует condition, потому что ваш макет (способ его настройки) не оценивает никаких условий, он всегда возвращает полный список.

InДругими словами, просто нет разницы, вызовет ли ваш GetProfessionalLessonsByTutorIdAsync метод GetEntities(condition) или GetEntities(), потому что макет настроен так, чтобы всегда возвращать полный список и игнорировать любое переданное ему условие.

И если вы измените код GetProfessionalLessonsByTutorIdAsync для запуска GetEntities().Where(condition), то вы, наконец, оцените condition against список, который GetEntities() возвращает.Проблема в том, что вы больше не можете контролировать то, что происходит с condition.

...