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

.NET Core Identity RoleManager对象Mock时Roles属性模拟问题

如何Mock RoleManager的Roles属性来测试GetListAsync方法

我在测试RoleService的GetListAsync()方法时遇到问题,该方法通过_roleManager.Roles.ToListAsync()获取角色列表并转换为RoleDto返回。需要Mock RoleManager对象的Roles属性,请问该如何实现?

RoleService代码

public class RoleService : IRoleService
{
    private readonly RoleManager<Role> _roleManager;
    private readonly IMapper _mapper;

    public RoleService(RoleManager<Role> roleManager, IMapper mapper = null)
    {
        _roleManager = roleManager;
        _mapper = mapper;
    }
    public async Task<List<RoleDto>> GetListAsync()
    {

        var roles = await _roleManager.Roles.ToListAsync();

        if (roles == null)
            throw new NotFoundException(ResponseCode.Exception, ErrorMessageKey.ROLE_NOTFOUND);

        return _mapper.Map<List<RoleDto>>(roles);
    }
 }

测试代码

public class RoleServiceTest
{
    private Mock<RoleManager<Role>> _mockRoleManager;
    private RoleManager<Role> _roleManager;
    private RoleService _roleService;
    private IMapper _mapper;

    private readonly List<Role> _roles;

    public RoleServiceTest()
    {
        var myProfile = new MappingProfile();
        var configuration = new MapperConfiguration(cfg => cfg.AddProfile(myProfile));
        _mapper = new Mapper(configuration);
        _mockRoleManager = GetRoleManagerMock();
        _roleManager = _mockRoleManager.Object;
        _roleService = new RoleService(_roleManager, _mapper);

        _roles = GetFakerRoles();
    }

    [Fact]
    public async Task GetListAsync_ValidInput_RoleDto()
    {
        // mocking code 

        var result = await _roleService.GetListAsync();

        Assert.NotNull(result);
        Assert.IsType<List<RoleDto>>(result);
    }

    private Mock<RoleManager<Role>> GetRoleManagerMock()
    {
        return new Mock<RoleManager<Role>>(
            new Mock<IRoleStore<Role>>().Object,
            new IRoleValidator<Role>[0],
            new Mock<ILookupNormalizer>().Object,
            new Mock<IdentityErrorDescriber>().Object,
            new Mock<ILogger<RoleManager<Role>>>().Object);
    }

    private List<Role> GetFakerRoles()
    {
        return new Faker<Role>()
             .RuleFor(r => r.Id, f => f.Random.Guid().ToString())
             .RuleFor(r => r.Name, f => f.Random.Words())
             .RuleFor(r => r.NormalizedName, (f, r) => r.Name.ToUpper())
             .RuleFor(r => r.ConcurrencyStamp, f => f.Random.ToString())
             .Generate(4);
    }
}

解决方案

RoleManager<T>的Roles是只读属性,底层依赖IRoleStore<T>提供数据,有两种可行的Mock方式:

方式1:Mock IRoleStore的查询逻辑

RoleManager.Roles本质调用IRoleStore<T>的Queryable属性,因此可以Mock该属性返回测试数据,适合多个测试共享数据:

修改GetRoleManagerMock()方法:

private Mock<RoleManager<Role>> GetRoleManagerMock()
{
    var mockRoleStore = new Mock<IRoleStore<Role>>();
    // 让RoleStore返回测试角色的查询集合
    mockRoleStore.Setup(s => s.Queryable).Returns(_roles.AsQueryable());

    return new Mock<RoleManager<Role>>(
        mockRoleStore.Object,
        new IRoleValidator<Role>[0],
        new Mock<ILookupNormalizer>().Object,
        new Mock<IdentityErrorDescriber>().Object,
        new Mock<ILogger<RoleManager<Role>>>().Object);
}

方式2:直接Mock RoleManager的Roles属性

若需要为单个测试定制返回数据,可直接用SetupGet设置Roles属性:

在GetListAsync_ValidInput_RoleDto()测试方法中添加Mock代码:

[Fact]
public async Task GetListAsync_ValidInput_RoleDto()
{
    // Mock Roles属性返回测试角色集合
    _mockRoleManager.SetupGet(r => r.Roles).Returns(_roles.AsQueryable());

    var result = await _roleService.GetListAsync();

    Assert.NotNull(result);
    Assert.IsType<List<RoleDto>>(result);
    // 可额外验证转换后的Dto数量是否匹配
    Assert.Equal(_roles.Count, result.Count);
}

注意事项

  • 确保_roles集合在Mock前已完成初始化(测试构造函数中已处理)
  • 方式1适合全局共享测试数据,方式2灵活性更高,可针对单个测试调整返回值

内容的提问来源于stack exchange,提问作者Bayram Eren

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 13:41:25