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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 16:02:48