.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
相关产品推荐
相关产品推荐

