You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MOQ配置疑问:如何正确设置MockRepository返回过滤后的IEnumerable<T>

Fixing Moq Setup for FindBy Method Filtering

Hey there! Let's break down why your Moq setup isn't working as expected and fix it step by step.

The Core Issue: Incorrect Setup Matching

Your main problem lies in how you're setting up the FindBy method on your mock repository. Looking at your code:

mockRepository.Setup(x => x.FindBy(x => It.IsAny<IAsyncRepository<Task>>()))
              .Returns(System.Threading.Tasks.Task.FromResult((IEnumerable<Task>)tasks.Where(x => x.Id == taskCurr.Id)));

This setup is trying to match a FindBy call that takes an IAsyncRepository<Task> parameter—but your actual FindBy method (used in the handler) accepts an Expression<Func<Task, bool>> (the filter lambda x => x.Id != command.Id). Since the parameter types don't match, Moq ignores this setup entirely:

  • When you use SetReturnsDefault, it falls back to returning the full list of tasks every time.
  • When you only use this incorrect setup, Moq can't find a matching setup and returns an empty list by default.

The Correct Setup Approach

Instead of hardcoding a filter in your setup, you need to tell Moq to apply the incoming filter expression to your test task list. This way, whatever lambda the handler passes to FindBy will actually filter the tasks you've created.

Replace your mock setup with this:

// Setup FindBy to apply the incoming predicate to your test tasks
mockRepository.Setup(repo => repo.FindBy(It.IsAny<Expression<Func<Task, bool>>>()))
              .ReturnsAsync((Expression<Func<Task, bool>> predicate) => 
                  tasks.Where(predicate.Compile()).ToList());

What This Does:

  1. It.IsAny<Expression<Func<Task, bool>>>() tells Moq to match any call to FindBy that passes a filter lambda.
  2. ReturnsAsync takes the incoming predicate, compiles it into a usable function, and applies it to your tasks list—returning only the items that match the filter.

Why This Fixes Your Test

When your handler runs this line:

var tasks = await _repository.FindBy(x => x.Id != command.Id);

Moq will take the x => x.Id != command.Id predicate, apply it to your tasks list (which contains taskPrev and taskCurr), and return only taskCurr (since its ID is taskId + 1, not equal to command.Id which is taskId). This means the subsequent overlap check won't find any conflicting tasks, so the BusinessException won't be thrown, and your test will pass.

Additional Tips

  • Remove SetReturnsDefault for the repository: Now that your setup correctly handles any filter, you don't need a default return value—it will override your specific setup anyway.
  • Use ReturnsAsync instead of Task.FromResult: It's cleaner and designed for async methods in Moq.
  • Ensure Task properties are accessible: Make sure the Id, TimeSheetId, Date, etc., properties on your Task class are public—otherwise, the compiled predicate won't be able to read them correctly.

Final Corrected Mock Setup Snippet

Here's how that section of your test should look after the fix:

//Criar 1ª Task
Task taskPrev = new Task(taskTypeId, projectId, costCenterId, Convert.ToDateTime(date), startHour, startMinute, endHour, endMinute, workItem, timeSheetId, description);
taskPrev.Id = taskId;
//Criar 2ª Task
Task taskCurr = new Task(taskTypeId, projectId, costCenterId, Convert.ToDateTime(date), endHour, startMinute, Convert.ToByte(endHour + 1), endMinute, workItem, timeSheetId, description);
taskCurr.Id = taskId + 1;
List<Task> tasks = new List<Task>();
tasks.Add(taskPrev);
tasks.Add(taskCurr);

// Correct Moq setup for FindBy
mockRepository.Setup(repo => repo.FindBy(It.IsAny<Expression<Func<Task, bool>>>()))
              .ReturnsAsync((Expression<Func<Task, bool>> predicate) => 
                  tasks.Where(predicate.Compile()).ToList());

内容的提问来源于stack exchange,提问作者Yasmin Kruger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 21:42:35