如何为SaveAsync方法编写单元测试并验证用户保存状态?
问题背景
我需要为以下SaveAsync方法编写单元测试,该方法可正常添加并保存用户:
待测试的SaveAsync方法
public async Task<UserModel> SaveAsync(UserModel model) { if (string.IsNullOrEmpty(model.ExternalUserId)) { var extUser = await identityManagementService.CreateUser(model); user = new ApplicationUser() { ExternalUserId = extUser.UserId, IsActive = true, UserName = model.Email, }; user.Id = Guid.NewGuid(); var exists = false; await applicationUserRepository.AddOrUpdateAsync(user, a => exists); } await applicationUserRepository.SaveAsync(); var IsSaved = await identityManagementService.GetUserById(user.ExternalUserId); // 验证用户是否保存成功 return model; }
我编写的单元测试代码
[Fact] public async Task SaveAsync_Should_AddORUpdate_WhenExternalUserIdDoesNOtExsitsAndProfileImgIsNull() // 角色已存在 { var userModel = UserMockData.UserCorrectModelWithExternalUsserIdEmpty(); var applicationRole = UserMockData.ApplicationRole(); _identityManagementService.Setup(x => x.CreateUser(userModel)).Returns(Task.FromResult(UserMockData.User())); // _identityManagementService.Setup(x => x.GetUserById(userModel.ExternalUserId)).Returns(() => null); _applicationRoleRepository.Setup(x => x.FindAsync(userModel.RoleId)).Returns(Task.FromResult(applicationRole)); _identityManagementService.Setup(x => x.AssignUserRoles(It.Is<String>(g => g != String.Empty), applicationRole.ExternalRoleId)).Returns(Task.FromResult(true)); var sut = new UserManagementService( _applicationRoleRepository.Object, _applicationUserRepository.Object, _applicationRolePermissionRepository.Object, _identityManagementService.Object, _smtpEmailService.Object, _logger.Object ); // 执行测试 var result = await sut.SaveAsync(userModel); // 断言 result.Should().NotBeNull(); var x = _identityManagementService.Object.GetUserById(userModel.ExternalUserId).Result; // 此处返回null var y = _applicationRoleRepository.Object.ListAsync(false).Result?.Count(); // 此处也返回null x.Should().Be(1); }
当前问题
实际调试SaveAsync方法时,var IsSaved = await identityManagementService.GetUserById(user.ExternalUserId)返回非null值,但在单元测试调试时该值为null。请指导我如何验证该方法是否成功保存用户。
解决方案
1. 修复GetUserById的Mock设置错误
测试中存在两个关键问题:
- 你传入
GetUserById的参数是userModel.ExternalUserId,但原方法中调用GetUserById时用的是CreateUser返回的extUser.UserId,而非原model的空值。 - 未正确设置
GetUserById的Mock返回值。
修改后的Mock代码:
var mockExtUser = UserMockData.User(); // 先捕获CreateUser返回的模拟用户对象 _identityManagementService.Setup(x => x.CreateUser(userModel)).Returns(Task.FromResult(mockExtUser)); // 匹配正确的参数,设置GetUserById的返回值 _identityManagementService.Setup(x => x.GetUserById(mockExtUser.UserId)).Returns(Task.FromResult(mockExtUser));
2. 用依赖调用验证替代直接结果查询(更规范的单元测试方式)
单元测试核心是验证被测方法是否正确调用了依赖组件的预期方法,而非直接查询Mock对象的结果。示例断言:
// 验证CreateUser被调用1次,参数正确 _identityManagementService.Verify(x => x.CreateUser(userModel), Times.Once); // 验证AddOrUpdateAsync被调用1次,且传入的用户对象符合预期 _applicationUserRepository.Verify(x => x.AddOrUpdateAsync( It.Is<ApplicationUser>(u => u.ExternalUserId == mockExtUser.UserId && u.UserName == userModel.Email), It.IsAny<Action<bool>>()), Times.Once); // 验证SaveAsync被调用1次 _applicationUserRepository.Verify(x => x.SaveAsync(), Times.Once); // 验证GetUserById被调用1次,参数为创建用户返回的UserId _identityManagementService.Verify(x => x.GetUserById(mockExtUser.UserId), Times.Once);
3. 修正错误的断言逻辑
原测试中x.Should().Be(1)完全错误,因为GetUserById返回的是用户对象而非数字。如果要验证返回结果,应改为:
var savedUser = await _identityManagementService.Object.GetUserById(mockExtUser.UserId); savedUser.Should().NotBeNull(); savedUser.UserId.Should().Be(mockExtUser.UserId);
4. 解决applicationRoleRepository.ListAsync返回null的问题
测试中未设置ListAsync的Mock返回值,所以调用时会返回null。如果需要验证角色列表,添加以下Mock设置:
_applicationRoleRepository.Setup(x => x.ListAsync(false)).Returns(Task.FromResult(new List<ApplicationRole> { applicationRole }));
内容的提问来源于stack exchange,提问作者hanushi-thana
相关产品推荐
相关产品推荐

