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

如何用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 12:57:26