James Bateman
James Bateman

Reputation: 83

Whats tests would sufficiently Unit Test a "Create" controller method in MVC?

I want to test this (Controller Method) :

public async Task<IActionResult> Create(SecurityQuestionViewModel securityQuestion)
{

    if (ModelState.IsValid)
    {
        SecurityQuestion dataModel = new SecurityQuestion();
        dataModel.questionText = securityQuestion.QuestionText;
        await _securityRepository.AddAsync(dataModel);

        return RedirectToAction("Index");
    }
    else
    {
        return View();
    }
}

My unit test (so far) looks like this ?

public async Task ModelContainsNewObjectAfterCreate()
{

    //Arrange

    _repository = new Mock<ISecurityQuestionRepository>();
    _repository.Setup(repo => repo.GetAllAsync()).Returns(Task.FromResult(securityQuestion()));
    _controller = new SecurityQuestionsController(_repository.Object, _mapper);

    SecurityQuestion dataModel = new SecurityQuestion();
                     dataModel.questionText = "This is the new added question";
    SecurityQuestionViewModel sqvm = new SecurityQuestionViewModel();
    sqvm.QuestionText = dataModel.questionText;

    //Act
    var result = await _controller.Create(sqvm);

    //Assert

    var viewResult = Assert.IsType<RedirectToActionResult>(result);
    _repository.Verify(r => r.AddAsync(dataModel), Times.Once);

}

The viewResult passes. The _repository verify does not.

It feels like I need to verify that the AddAsync method ran (would add a record to the existing repository). Perhaps my setup is wrong

It also feels like I need to validate the number of "questions" in the repository after the AddAsync method ran.

I am trying to understand what would constitute an adequate test and how to simulate the "Add" with the Moq.

Any insight would be appreciated.

This Post seems close to what I want.

Upvotes: 1

Views: 304

Answers (2)

kat1330
kat1330

Reputation: 5322

You can test only following things in your action:

  1. The case when the model is valid.
  2. The case when the model is invalid.

There are only two cases. If the first case is satisfied you can verify that AddAsync() is executed with any parameter which is type SecurityQuestion.

You can mock AddAsync() like this:

repository.Setup(r => r.AddAsync(It.IsAny<SecurityQuestion>())
         .Returns(Task.FromResult(false));

And verify:

repository.Verify(r => r.AddAsync(It.IsAny<SecurityQuestion>()), Times.Once);

That is all which you can!

You cannot mock SecurityQuestion model because it uses new keyword and your code which try to mock should be removed.

This is all you need to do because your entire logic is if/else statement. Everything else will be executed normally. Only another thing which can behave unexpectedly is if AddAsync() throws an exception.

Upvotes: 1

Nkosi
Nkosi

Reputation: 246998

The verify fails because the model was created within the method under test so it does not match. what you can do is use the It.Is with a predicate that matches the model properties

_repository.Verify(r => r.AddAsync(It.Is<SecurityQuestion>(m => m.questionText == dataModel.questionText)), Times.Once);

Upvotes: 1

Related Questions