.NET中MediatR结构的单元测试:无适配库时如何编写?
MediatR 单元测试实操方案
其实根本不需要专门的适配库——MediatR的组件都是基于接口设计的,用常规的单元测试框架(比如xUnit、NUnit)+ 模拟工具(Moq)就能搞定,下面是具体的测试场景和代码示例:
1. 直接测试请求处理程序(IRequestHandler)
处理程序本身就是普通类,直接实例化并注入依赖的模拟对象即可,完全不需要通过MediatR中介者调用。
示例代码
假设你有如下请求和处理程序:
public record CreateUserRequest(string Name) : IRequest<Guid>; public class CreateUserHandler : IRequestHandler<CreateUserRequest, Guid> { private readonly IUserRepository _userRepo; public CreateUserHandler(IUserRepository userRepo) { _userRepo = userRepo; } public async Task<Guid> Handle(CreateUserRequest request, CancellationToken cancellationToken) { var userId = Guid.NewGuid(); await _userRepo.AddUserAsync(new User(userId, request.Name), cancellationToken); return userId; } }
对应的测试代码(xUnit + Moq):
public class CreateUserHandlerTests { private readonly Mock<IUserRepository> _mockUserRepo; private readonly CreateUserHandler _handler; public CreateUserHandlerTests() { _mockUserRepo = new Mock<IUserRepository>(); _handler = new CreateUserHandler(_mockUserRepo.Object); } [Fact] public async Task Handle_ValidRequest_ReturnsNewUserIdAndCallsRepo() { // 准备测试数据 var request = new CreateUserRequest("Alice"); _mockUserRepo.Setup(x => x.AddUserAsync(It.IsAny<User>(), It.IsAny<CancellationToken>())) .Returns(Task.CompletedTask); // 执行测试 var result = await _handler.Handle(request, CancellationToken.None); // 验证结果 Assert.NotEqual(Guid.Empty, result); _mockUserRepo.Verify(x => x.AddUserAsync(It.Is<User>(u => u.Name == "Alice"), It.IsAny<CancellationToken>()), Times.Once); } }
2. 测试管道行为(IPipelineBehavior)
管道行为是包裹处理流程的中间件,测试时需要模拟请求和后续委托,验证行为的逻辑是否生效(比如验证、日志、异常处理等)。
示例代码
假设你有一个参数验证行为:
public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse> { private readonly IValidator<TRequest> _validator; public ValidationBehavior(IValidator<TRequest> validator) { _validator = validator; } public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken) { var validationResult = await _validator.ValidateAsync(request, cancellationToken); if (!validationResult.IsValid) { throw new ValidationException(validationResult.Errors); } return await next(); } }
对应的测试代码:
public class ValidationBehaviorTests { private readonly Mock<IValidator<CreateUserRequest>> _mockValidator; private readonly ValidationBehavior<CreateUserRequest, Guid> _behavior; public ValidationBehaviorTests() { _mockValidator = new Mock<IValidator<CreateUserRequest>>(); _behavior = new ValidationBehavior<CreateUserRequest, Guid>(_mockValidator.Object); } [Fact] public async Task Handle_InvalidRequest_ThrowsValidationException() { // 准备无效请求和验证错误 var request = new CreateUserRequest(""); var validationErrors = new List<ValidationFailure> { new ValidationFailure("Name", "名称不能为空") }; _mockValidator.Setup(x => x.ValidateAsync(request, It.IsAny<CancellationToken>())) .ReturnsAsync(new ValidationResult(validationErrors)); // 验证抛出异常 await Assert.ThrowsAsync<ValidationException>(() => _behavior.Handle(request, () => Task.FromResult(Guid.NewGuid()), CancellationToken.None)); } [Fact] public async Task Handle_ValidRequest_CallsNextDelegate() { // 准备有效请求 var request = new CreateUserRequest("Alice"); _mockValidator.Setup(x => x.ValidateAsync(request, It.IsAny<CancellationToken>())) .ReturnsAsync(new ValidationResult()); var isNextCalled = false; Task<Guid> NextDelegate() { isNextCalled = true; return Task.FromResult(Guid.NewGuid()); } // 执行测试 await _behavior.Handle(request, NextDelegate, CancellationToken.None); // 验证后续委托被调用 Assert.True(isNextCalled); } }
3. 测试完整的MediatR调度流程
如果需要验证MediatR是否能正确找到处理程序并完成调度,可以手动构建MediatR实例进行集成测试:
public class MediatrIntegrationTests { [Fact] public async Task SendRequest_MediatorFindsHandlerAndReturnsResult() { // 构建服务容器并注册MediatR及依赖 var services = new ServiceCollection(); services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(CreateUserHandler).Assembly)); var mockRepo = new Mock<IUserRepository>(); services.AddSingleton(mockRepo.Object); var provider = services.BuildServiceProvider(); var mediator = provider.GetRequiredService<IMediator>(); var request = new CreateUserRequest("Bob"); // 发送请求 var result = await mediator.Send(request); // 验证结果 Assert.NotEqual(Guid.Empty, result); mockRepo.Verify(x => x.AddUserAsync(It.Is<User>(u => u.Name == "Bob"), It.IsAny<CancellationToken>()), Times.Once); } }
内容的提问来源于stack exchange,提问作者Ershad Raoufi
相关产品推荐
相关产品推荐

