问题描述
这可能是由于我不了解xUnit和Moq的原因,但是我试图在控制器中测试post方法,但是在控制器中,我有以下代码行:
var user = await _mapModelService.MapModelForNewUser(viewmodel);
这会将viewmodel传递给服务,在服务中它将viewmodel属性映射到一个新的Model,以便以后将其写入数据库。
在测试中,我试图使用Moq来使用服务并返回新的Model。我的这段代码是这样的:
mapModelService.Setup(x => x.MapModelForNewUser(new NewUserVm())).ReturnsAsync(new User()
{
UserId = 1
});
我所需要的只是id,因此我可以在完成路由后测试路由值,但是控制器中的用户对象为null,并且测试失败,并显示NullReferenceException。我并不是要测试服务返回的对象,只是为了使测试运行。
我哪里出错了?
编辑:建议的答案不能回答我的问题,它似乎与我已经在做的非常相似。我尝试过创建viewmodel和Model的新实例,并为它们提供任意值,并以相同的结果传递这些值。
编辑2:服务是异步的,id的调用方式有所不同,但我印象ReturnsAsync()
处理了此问题。
编辑3:这是完整的测试。
[Fact]
public async Task NewUser_ShouldRedirectToNewCreatedUserWhenModelStateIsValid_WithUserDetailsVm()
{
// Arrange
var logger = new Mock<ILogger<UserController>>();
var vmService = new Mock<IviewmodelService>();
var userRepo = new Mock<IUserRepo>();
var mapModelService = new Mock<IMapModelService>();
var userController = new UserController(logger.Object,vmService.Object,userRepo.Object,mapModelService.Object);
var redirectToRouteResult = await userController.NewUser(It.IsAny<NewUserVm>()) as RedirectToRouteResult;
// Act
mapModelService.Setup(x => x.MapModelForNewUser(It.IsAny<NewUserVm>()))
.ReturnsAsync(new User()
{
UserId = 1
});
userController.ModelState.Clear();
// Assert
Assert.NotNull(redirectToRouteResult);
Assert.False(redirectToRouteResult.Permanent);
Assert.Equal("UserDetails",redirectToRouteResult.RouteValues["Action"]);
Assert.Equal("User",redirectToRouteResult.RouteValues["Controller"]);
Assert.Equal(1,redirectToRouteResult.RouteValues["id"]);
Assert.Equal("note",redirectToRouteResult.RouteValues["requiredTab"]);
}
解决方法
如果您不关心传入的视图模型,请在设置中使用It.IsAny<NewUserVm>()
。
另外,Setup
需要在调用被测对象之前完成
// Arrange
// ...omitted for brevity
mapModelService
.Setup(x => x.MapModelForNewUser(It.IsAny<NewUserVm>())) //<--NOTE THE ARGUMENT MATCHER
.ReturnsAsync(new User() {
UserId = 1
});
var viewModel = new NewUserVm();
// Act
var redirectToRouteResult = await userController.NewUser(viewModel) as RedirectToRouteResult;
// Assert
// ...
原始设置是使用特定实例完成的,在执行测试时将永远不会使用该实例。因此,该模拟永远不会像您期望的那样表现。
参考Moq Quickstart,以更好地了解其用法。