簡體   English   中英

表達<Func<T, bool> &gt; 在模擬設置中沒有按預期工作

[英]Expression<Func<T, bool>> is not working as expected in mock setup

這是我要測試的方法:

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)

您設置的問題在於您將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)模擬的調用,但它只是忽略了condition因為你的模擬(你設置它的方式)不評估任何條件,它總是返回完整列表。

換句話說,無論您的GetProfessionalLessonsByTutorIdAsync方法是調用GetEntities(condition)還是GetEntities()沒有區別,因為模擬設置為始終返回完整列表並忽略傳遞給它的任何條件。

如果您更改GetProfessionalLessonsByTutorIdAsync的代碼以運行GetEntities().Where(condition)那么您最終將根據GetEntities()返回的列表評估condition 這樣做的問題是您不再能夠控制condition發生的事情。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM