在Moq中使用UserManager接口

4

因此,我正在尝试使用xunit进行单元测试,并且需要模拟一个接口,其中它的存储库使用UserManager。 我认为这里发生的情况是,在进行单元测试时未初始化UserManager,因为如果运行应用程序,则可以正常工作。

IUserRepository接口:

public interface IUserRepository : IDisposable
    {
        Task<List<ApplicationUser>> ToListAsync();
        Task<ApplicationUser> FindByIDAsync(string userId);
        Task<ApplicationUser> FindByNameAsync(string userName);
        Task<IList<string>> GetRolesAsync(ApplicationUser user);
        Task AddToRoleAsync(ApplicationUser user, string roleName);
        Task RemoveFromRoleAsync(ApplicationUser user, string roleName);
        Task<bool> AnyAsync(string userId);
        Task AddAsync(ApplicationUser user);
        Task DeleteAsync(string userId);
        void Update(ApplicationUser user);
        Task SaveChangesAsync();
    }

UserRepository:

public class UserRepository : IUserRepository
    {
        private readonly ApplicationDbContext _context;
        private readonly UserManager<ApplicationUser> _userManager;

        public UserRepository(ApplicationDbContext context, UserManager<ApplicationUser> userManager)
        {
            _context = context;
            _userManager = userManager;
        }

        public Task<ApplicationUser> FindByIDAsync(string userId)
        {
            return _context.ApplicationUser.FindAsync(userId);
        }

        public Task<ApplicationUser> FindByNameAsync(string userName)
        {
            return _context.ApplicationUser.SingleOrDefaultAsync(m => m.UserName == userName);
        }

        public Task<List<ApplicationUser>> ToListAsync()
        {
            return _context.ApplicationUser.ToListAsync();
        }

        public Task AddAsync(ApplicationUser user)
        {
            _context.ApplicationUser.AddAsync(user);
            return _context.SaveChangesAsync();
        }

        public void Update(ApplicationUser user)
        {
            _context.Entry(user).State = EntityState.Modified;
        }

        public Task DeleteAsync(string userId)
        {
            ApplicationUser user = _context.ApplicationUser.Find(userId);
            _context.ApplicationUser.Remove(user);
            return _context.SaveChangesAsync();
        }

        public Task<IList<string>> GetRolesAsync(ApplicationUser user)
        {
            return _userManager.GetRolesAsync(user);
        }

        public Task AddToRoleAsync(ApplicationUser user, string roleName)
        {
            _userManager.AddToRoleAsync(user, roleName);
            return _context.SaveChangesAsync();
        }

        public Task RemoveFromRoleAsync(ApplicationUser user, string roleName)
        {
            _userManager.RemoveFromRoleAsync(user, roleName);
            return _context.SaveChangesAsync();
        }

        private bool disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    _context.Dispose();
                }
            }
            this.disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        public Task<bool> AnyAsync(string userId)
        {
            return _context.ApplicationUser.AnyAsync(e => e.Id == userId);
        }

        public Task SaveChangesAsync()
        {
            return _context.SaveChangesAsync();
        }
    }

用户控制器(仅限索引):

public class UserController : CustomBaseController
    {
        private readonly IUserRepository _userRepository;
        private readonly IRoleRepository _roleRepository;

        public UserController(IUserRepository userRepository,IRoleRepository roleRepository)
        {
            _userRepository = userRepository;
            _roleRepository = roleRepository;
        }

        // GET: User
        public async Task<IActionResult> Index()
        {
            List<ApplicationUser> ListaUsers = new List<ApplicationUser>();
            List<DadosIndexViewModel> ListaUsersModel = new List<DadosIndexViewModel>();
            List<Tuple<ApplicationUser, string>> ListaUserComRoles = new List<Tuple<ApplicationUser, string>>();
            var modelView = await base.CreateModel<IndexViewModel>(_userRepository);

            ListaUsers = await _userRepository.ToListAsync();

            foreach(var item in ListaUsers)
            {
                //Por cada User que existir na ListaUsers criar um objecto novo?
                DadosIndexViewModel modelFor = new DadosIndexViewModel();

                //Lista complementar para igualar a modelFor.Roles -> estava a dar null.
                var tempList = new List<string>();

                //Inserir no Objeto novo o user.
                modelFor.Nome = item.Nome;
                modelFor.Email = item.Email;
                modelFor.Id = item.Id;
                modelFor.Telemovel = item.PhoneNumber;

                //Buscar a lista completa de roles por cada user(item).
                var listaRolesByUser = await _userRepository.GetRolesAsync(item);

                //Por cada role que existir na lista comp
                foreach (var item2 in listaRolesByUser)
                    {
                        //Não é preciso isto mas funciona. Array associativo.
                        ListaUserComRoles.Add(new Tuple<ApplicationUser, string>(item, item2));
                        //Adicionar cada role à lista
                        tempList.Add(item2);
                    }
                modelFor.Roles = tempList;
                //Preencher um objeto IndexViewModel e adiciona-lo a uma lista até ter todos os users.
                ListaUsersModel.Add(modelFor);
            }
        //Atribuir a lista de utilizadores à lista do modelo (DadosUsers)
        modelView.DadosUsers = ListaUsersModel;
        //return View(ListaUsersModel);
        return View(modelView);
    }

并进行测试:

public class UserControllerTest
    {
        [Fact]
        public async Task Index_Test()
        {

            // Arrange
            var mockUserRepo = new Mock<IUserRepository>();
            mockUserRepo.Setup(repo => repo.ToListAsync()).Returns(Task.FromResult(getTestUsers()));
            var mockRoleRepo = new Mock<IRoleRepository>();
            mockRoleRepo.Setup(repo => repo.ToListAsync()).Returns(Task.FromResult(getTestRoles()));

            var controller = new UserController(mockUserRepo.Object, mockRoleRepo.Object);

            controller.ControllerContext = new ControllerContext
            {
                HttpContext = new DefaultHttpContext
                {
                    User = new ClaimsPrincipal(new ClaimsIdentity())
                }
            };
            // Act
            var result = await controller.Index();

            // Assert
            var viewResult = Assert.IsType<ViewResult>(result);
            var model = Assert.IsAssignableFrom<IndexViewModel>(viewResult.ViewData.Model);
            Assert.Equal(2,model.DadosUsers.Count);
        }

        private List<ApplicationUser> getTestUsers()
        {
            var Users = new List<ApplicationUser>();

            Users.Add(new ApplicationUser()
            {
                Nome = "Leonardo",
                UserName = "leonardo@teste.com",
                Email = "leonardo@teste.com",
                PhoneNumber= "911938567"
            });

            Users.Add(new ApplicationUser()
            {
                Nome = "José",
                UserName = "José@teste.com",
                Email = "José@teste.com",
                PhoneNumber = "993746738"
            });

            return Users;
        }

        private List<IdentityRole> getTestRoles()
        {
            var roles = new List<IdentityRole>();

            roles.Add(new IdentityRole()
            {
                Name = "Admin",
                NormalizedName = "ADMIN"
            });
            roles.Add(new IdentityRole()
            {
                Name = "Guest",
                NormalizedName = "GUEST"
            });

            return roles;
        }
    }

问题是:在UserController上,我有var listaRolesByUser = await _userRepository.GetRolesAsync(item);,当应用程序运行时它可以正常工作,但是当我运行测试时,GetRolesAsync()方法返回null,或者listaRolesByUser没有被初始化。
抱歉如果这看起来有点混乱,我不知道这是否是正确的做法,但这是我迄今为止学到的。
1个回答

2

您需要在模拟对象上设置GetRolesAsync(item)方法,否则Moq将从中返回null。

因此,请将以下代码放置在模拟用户存储库的声明下方:

mockUserRepo.Setup(repo => repo.GetRolesAsync()).Returns(Task.FromResult(getUsersExpectedRoles()));

这应该确保您的getUsersExpectedRoles()方法的结果被返回,而不是null,并且它与您想要模拟的用户类型匹配。
总的来说,您必须明确声明您想在moq对象上设置的方法。因此,任何被测试目标调用的方法,都需要与之关联的设置。

方法 GetRolesAsync(item) 应返回用户(item)的角色。我没有展示那个 getTestRoles() 方法,我的错误。getTestRoles() 是一个包含示例角色的 List。我会添加它的。我正在仓储中使用 UserManager 从用户(item)返回用户角色。 - Leonardo Henriques
@LeonardoHenriques 不管需要调用什么方法,你只需要让它返回你需要模拟的特定测试数据即可。 - gmn
谢谢您的帮助,我会尝试去做的。@gmn - Leonardo Henriques
@LeonardoHenriques 不用担心,我已经更新了我的答案,更加具体地针对你在这里告诉我的内容。 - gmn
我明白了。一开始我不确定这些都是怎么工作的,我无法将正确的用户传递给方法,我只需要放置 GetRolesAsync(It.IsAny<ApplicationUser>()) 并创建一个新的方法来为用户创建角色。谢谢。 - Leonardo Henriques

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接