从服务中获取一个对象,以允许使用xUnit和Moq运行测试



这可能是由于我对xUnit和Moq不了解,但我正在尝试在控制器中测试post方法,但在控制器中,我有以下代码行:

var user = await _mapModelService.MapModelForNewUser(viewModel);

这将把ViewModel传递给服务,在那里它将ViewModel属性映射到一个新模型,以便稍后将其写入数据库。

在测试中,我试图使用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
// ...

最初的设置是使用一个特定的实例完成的,在进行测试时永远不会使用该实例。因此,mock的行为永远不会像你所期望的那样。

参考Moq Quickstart以更好地了解如何使用它。

最新更新