简体   繁体   English

从服务获取 object 以允许使用 xUnit 和 Moq 运行测试

[英]Get an object from a service to allow test to run using xUnit and Moq

This is probably due to my lack of understanding as I'm new to xUnit and Moq but I'm trying to test a post method in my controller, however in the controller, I have this line of code:这可能是由于我缺乏理解,因为我是 xUnit 和 Moq 的新手,但我正在尝试在我的 controller 中测试 post 方法,但是在 controller 中,我有这行代码:

var user = await _mapModelService.MapModelForNewUser(viewModel);

This will pass the ViewModel to the service where it maps the ViewModel properties to a new Model ready for it to be written to the database later.这会将 ViewModel 传递给服务,在该服务中它将 ViewModel 属性映射到新的 Model 以便稍后将其写入数据库。

In the test, I'm trying to use Moq to use the service and return a new Model.在测试中,我尝试使用 Moq 来使用服务并返回一个新的 Model。 This code I have is like so:我拥有的这段代码是这样的:

mapModelService.Setup(x => x.MapModelForNewUser(new NewUserVm())).ReturnsAsync(new User()
{
    UserId = 1
});

All I need is the id so I can test the route values once it's finished, however the user object in the controller is null and the test fails with a NullReferenceException.我所需要的只是 id,因此我可以在完成后测试路由值,但是 controller 中的用户 object 是 null 并且测试失败并出现 NullReferenceException。 I'm not trying to test the object the service returns, it's just so the test runs.我不是要测试服务返回的 object,只是为了测试运行。

Where have I gone wrong?我哪里出错了?

EDIT: The suggested answer does not answer my question, it appears to be very similar to what I'm already doing.编辑:建议的答案没有回答我的问题,它似乎与我已经在做的非常相似。 I've tried creating new instances of ViewModel and Model and giving them arbitrary values and passing those instead, with the same result.我尝试创建 ViewModel 和 Model 的新实例,并给它们任意值并传递它们,结果相同。

EDIT 2: The service is asynchronous, id that makes a difference how this is called but I was under the impression ReturnsAsync() handles this.编辑 2:该服务是异步的,id 这会有所不同,但我的印象是ReturnsAsync()处理这个。

EDIT 3: Here's the full test.编辑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"]);
        }

If you do not care about the viewmodel being passed in then use It.IsAny<NewUserVm>() in the setup.如果您不关心传入的视图模型,请在设置中使用It.IsAny<NewUserVm>()

Also the Setup needs to be done before invoking the subject under test还需要在调用被测对象之前完成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

// ...

The original setup was done with a specific instance that will never be used when exercising the test.原始设置是使用特定实例完成的,在进行测试时永远不会使用该实例。 Thus the mock will never behave as you would expect.因此,模拟永远不会像您期望的那样表现。

Reference Moq Quickstart for a better understanding of how to use it.参考Moq Quickstart以更好地了解如何使用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM