Moq模拟仓储传入参数返回结果不符的问题排查
问题描述
我要测试一个接收division字符串参数的方法,为此创建了模拟仓储。仓储里有3个对象:2个Division为"NYC",1个为"LAX"。向模拟对象传入参数"NYC"时,期望返回2个对象(用Shouldly的Count方法断言),但实际报错显示返回了3个。直接调用Handler操作数据库时能正确返回2个对象,是不是参数传递出问题了?
相关代码
待模拟的接口
// interface to mock public interface IUserRepository<UserDto> { Task<IReadOnlyList<UserDto>> ListAllActiveUsers(string division); }
请求类
// Request public class GetUserListQuery : IRequest<List<UserListVm>> { public string Division { get; set; } }
请求处理器
// Request Handler public class GetUserListQueryHandler : IRequestHandler<GetUserListQuery, List<UserListVm>> { private readonly IUserRepository<UserDto> _userRepository; private readonly IMapper _mapper; public GetUserListQueryHandler(IUserRepository<UserDto> userRepository, IMapper mapper) { _userRepository = userRepository; _mapper = mapper; } public async Task<List<UserListVm>> Handle(GetUserListQuery request, CancellationToken cancellationToken) { var allUsers = (await _userRepository.ListAllActiveUsers(request.Division)).OrderBy(o => o.Id); return _mapper.Map<List<UserListVm>>(allUsers); } }
仓储模拟类
// Repository mock public class UserRepositoryMocks { public static Mock<IUserRepository<UserDto>> GetUserRepository() { var users = new List<UserDto> { new UserDto { Id = 1, UserName = "Mike Smith", Division = "NYC", IsActive = true }, new UserDto { Id = 2, UserName = "Rob Michael", Division = "NYC", IsActive = true }, new UserDto { Id = 5, UserName = "Carl Jackson", Division = "LAX", IsActive = true } }; var mockUserRepository = new Mock<IUserRepository<UserDto>>(); mockUserRepository.Setup(repo => repo.ListAllActiveUsers(It.IsAny<string>())).ReturnsAsync(users); return mockUserRepository; } }
xUnit测试类
// xUnit test public class GetUserListQueryHandlerTests { private readonly IMapper _mapper; private readonly Mock<IUserRepository<UserDto>> _mockUserRepository; public GetUserListQueryHandlerTests() { _mockUserRepository = UserRepositoryMocks.GetUserRepository(); var configProvider = new MapperConfiguration(cfg => { cfg.AddProfile<MappingProfile>(); }); _mapper = configProvider.CreateMapper(); } [Fact] public async Task GetUsersListTest() { // Arrange var handler = new GetUserListQueryHandler(_mockUserRepository.Object, _mapper); // Act var result = await handler.Handle(new GetUserListQuery() { Division = "NYC" }, CancellationToken.None); // Assert result.ShouldBeOfType<List<UserListVm>>(); result.Count.ShouldBe(2); } }
真实仓储实现类(补充)
public async Task<IReadOnlyList<UserDto>> ListAllActiveUsers(string division) { var dbDataUsers = new List<User>(); if (division != null) { dbDataUsers = await _dbContext.Users .AsNoTracking() .Where(x => x.IsActive == true && x.Division == division) .ToListAsync(); } else { dbDataUsers = await _dbContext.Users .AsNoTracking() .Where(x => x.IsActive == true) .ToListAsync(); } return _mapper.Map<List<UserDto>>(dbDataUsers); }
问题原因与修复
问题出在模拟仓储的Setup配置上:
你当前的模拟设置是mockUserRepository.Setup(repo => repo.ListAllActiveUsers(It.IsAny<string>())).ReturnsAsync(users);,这意味着不管传入任何division参数,模拟仓储都会返回全部3个用户对象,完全忽略了参数的过滤逻辑。而真实仓储的实现会根据传入的division值过滤数据,所以真实环境下结果正确。
修复方法有两种:
方法1:让模拟仓储根据参数过滤数据
修改模拟仓储的Setup逻辑,根据传入的division参数筛选返回的用户:
mockUserRepository.Setup(repo => repo.ListAllActiveUsers(It.IsAny<string>())) .ReturnsAsync((string division) => users.Where(u => u.Division == division).ToList());
方法2:针对测试用例的特定参数设置返回值
如果只想针对当前测试用例的"NYC"参数设置返回结果,可以直接指定参数匹配:
mockUserRepository.Setup(repo => repo.ListAllActiveUsers("NYC")) .ReturnsAsync(users.Where(u => u.Division == "NYC").ToList());
这样修改后,测试用例就能正确返回2个NYC的用户,断言通过。
内容的提问来源于stack exchange,提问作者mustafa00
相关产品推荐
相关产品推荐

