如何编写访问工作单元的单元测试用例?Mock时遇构造函数报错求解
解决“无法实例化类的代理,找不到无参构造函数”的Mock问题
嘿,这个报错我太熟了!大概率是你Mock依赖的方式出了问题,结合你提到的UserManagement类和传入Mock UnitOfWork的场景,咱们一步步来搞定:
1. 先搞清楚UserManagement的构造函数到底依赖啥
你给的代码片段里显示它有多个私有仓库属性,但你说传入的是Mock的UnitOfWork——我猜你的UserManagement实际是通过IUnitOfWork来获取这些仓库的,对吧?比如构造函数大概是这样:
public class UserManagement : IUserManagement { private readonly IEntityBaseRepository<User> _userRepository; private readonly IEntityBaseRepository<Role> _roleRepository; public UserManagement(IUnitOfWork unitOfWork) { _userRepository = unitOfWork.GetRepository<User>(); _roleRepository = unitOfWork.GetRepository<Role>(); } // 你的添加用户方法 public void AddUser(User user, IEnumerable<string> roleNames) { // ...业务逻辑 } }
如果是这样,那问题十有八九是你Mock的是具体的UnitOfWork类,而不是它的接口IUnitOfWork!Moq要创建具体类的代理,必须要求这个类有公开的无参构造函数,不然就会报你看到的错。
2. 正确的Mock姿势:Mock接口,别Mock具体类
赶紧把Mock对象换成接口,代码这么写:
// 第一步:Mock IUnitOfWork接口(这才是正确的打开方式) var mockUnitOfWork = new Mock<IUnitOfWork>(); // 第二步:给每个仓库的GetRepository<T>方法Mock返回值 var mockUserRepo = new Mock<IEntityBaseRepository<User>>(); mockUnitOfWork.Setup(uow => uow.GetRepository<User>()).Returns(mockUserRepo.Object); var mockRoleRepo = new Mock<IEntityBaseRepository<Role>>(); mockUnitOfWork.Setup(uow => uow.GetRepository<Role>()).Returns(mockRoleRepo.Object); // 第三步:实例化被测的UserManagement,传入Mock的实例(注意是.Object属性!) var userManagement = new UserManagement(mockUnitOfWork.Object);
3. 如果你的UserManagement直接依赖多个仓库
要是你的UserManagement构造函数是直接注入各个仓库接口,比如:
public UserManagement(IEntityBaseRepository<User> userRepository, IEntityBaseRepository<Role> roleRepository) { _userRepository = userRepository; _roleRepository = roleRepository; }
那你根本不需要传UnitOfWork,直接Mock每个仓库然后注入就行:
var mockUserRepo = new Mock<IEntityBaseRepository<User>>(); var mockRoleRepo = new Mock<IEntityBaseRepository<Role>>(); var userManagement = new UserManagement(mockUserRepo.Object, mockRoleRepo.Object);
4. 万不得已要Mock具体类?(不推荐)
如果因为某些限制必须Mock具体的UnitOfWork类,那你要么给这个类加个公开的无参构造函数,要么在创建Mock的时候指定构造函数的参数:
// 假设UnitOfWork需要传入DbContext var mockDbContext = new Mock<MyDbContext>(); var mockUnitOfWork = new Mock<UnitOfWork>(mockDbContext.Object);
不过真心不推荐这么干,Mock具体类会让你的测试和实现耦合得太死,以后改代码容易崩。
最后检查个小细节
别犯这种低级错误:实例化UserManagement的时候,你传的是mockUnitOfWork.Object,而不是mockUnitOfWork本身!很多人刚开始用Moq都会忘加.Object,也会导致奇怪的报错。
内容的提问来源于stack exchange,提问作者DotNetUser
相关产品推荐
相关产品推荐

