如何用NUnit测试MediatR Handler?仅Mock仓储不Mock中介与处理器
测试MediatR Handler时直接调用而非Mock的解决方案
问题描述
想要测试API中由MediatR调用的Handler,但测试用例中无法触发Handler执行。需求是仅Mock仓储依赖,不Mock MediatR或Handler本身,但当前代码中mediator未正确初始化,导致Send方法无法执行。
解决方案
方案一:直接实例化Handler并调用Handle方法(推荐)
测试Handler的核心逻辑时,完全不需要通过MediatR中介器中转。直接构造Handler实例,传入Mock的仓储依赖,调用其Handle方法即可完成测试,步骤更简洁高效。
修改后的测试代码示例:
using NUnit.Framework; using Domain.Model; using Core.Handlers.TimerRegister; using Moq; using Repository.IRepository; using System; using System.Collections.Generic; using System.Threading; namespace EmployeeRegisterTest.CoreTest { [TestFixture] public class TimerRegisterTest { private Mock<IEmployeeRepository> _employeeRepositoryMock; private Mock<IEmployeeTimeRegister> _timerRegisterRepositoryMock; private TimerRegisterCommandHandler _handler; [SetUp] public void Setup() { _employeeRepositoryMock = new Mock<IEmployeeRepository>(); _timerRegisterRepositoryMock = new Mock<IEmployeeTimeRegister>(); // 直接构造Handler,传入Mock的仓储实例 _handler = new TimerRegisterCommandHandler( _employeeRepositoryMock.Object, _timerRegisterRepositoryMock.Object); } [Test] public async Task MustRegisterTimeCorrectly() { var employee = new Employee { Email = "JorgeEmailTest@email.com", EmployeeName = "Jorge", Password = "$2a$11$p0655c8x/QoQAjnor0vT8eoK6OagnT1g34b/YN9NkPOtsvlFf828G", Role = "mananger", Id = 2 }; var timeRegister = new TimeRegister { Employee = employee, Id = 1, EmployeeTimeRegister = DateTime.Now }; var timerRegistarList = new List<TimeRegister> { timeRegister }; var timeRegisterCommandRequest = new TimeRegisterCommandRequest { EmployeeEmail = employee.Email, EmployeeName = employee.EmployeeName, }; // 配置Mock仓储的返回逻辑 _employeeRepositoryMock.Setup(x => x.GetEmployee("JorgeEmailTest@email.com")) .Returns(Task.FromResult(employee)); // 避免DateTime.Now的时间差问题,用It.IsAny<DateTime>()匹配任意时间 _timerRegisterRepositoryMock.Setup(x => x.GetTodayTimeRegisterByEmployeeAndDate(employee, It.IsAny<DateTime>())) .Returns(Task.FromResult(timerRegistarList)); // 直接调用Handler的Handle方法 var result = await _handler.Handle(timeRegisterCommandRequest, CancellationToken.None); // NUnit正确的相等断言方法是Assert.AreEqual Assert.AreEqual(result.message, "Register created successfuly"); } } }
关键修改点
- 在
SetUp方法中初始化Mock仓储和Handler实例,将Mock对象直接注入Handler构造函数。 - 替换
mediator.Send为直接调用Handler的Handle方法,省去MediatR中介环节。 - 修复
DateTime.Now的匹配问题:Setup时的时间和测试执行时的时间可能不一致,用It.IsAny<DateTime>()避免断言失败。 - 修正断言方法:将
Assert.Equals改为NUnit标准的Assert.AreEqual。
方案二:配置MediatR测试容器(若必须使用mediator.Send)
如果需要模拟真实环境中的MediatR调用流程,可以通过依赖注入容器注册Handler和Mock仓储,构建测试用的IMediator实例:
using Microsoft.Extensions.DependencyInjection; using MediatR; [SetUp] public void Setup() { _employeeRepositoryMock = new Mock<IEmployeeRepository>(); _timerRegisterRepositoryMock = new Mock<IEmployeeTimeRegister>(); var services = new ServiceCollection(); // 注册MediatR及目标Handler所在程序集的服务 services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining<TimerRegisterCommandHandler>()); // 替换仓储为Mock实例 services.AddSingleton(_employeeRepositoryMock.Object); services.AddSingleton(_timerRegisterRepositoryMock.Object); var serviceProvider = services.BuildServiceProvider(); _mediator = serviceProvider.GetRequiredService<IMediator>(); }
此方法更贴近生产环境,但步骤繁琐,仅在需要测试MediatR调度逻辑时使用。
内容的提问来源于stack exchange,提问作者Mateus Souza
相关产品推荐
相关产品推荐

