lloydphillips
lloydphillips

Reputation: 2855

Using moq to verify a method is called on an mvc controller

I'm testing an MVC controller and want to test that a Save method is called within one of my repositories. The controller is an AccountController which is attempting to Register a user. My AccountRepository has two methods, Save and Register. Register is calling Save after some checks. I'm not sure if I should just be testing whether Register gets called and running a seperate unit test on my Repository to verify if Save is called as part of calling Register or whether I've set up Moq incorrectly on my test.

Here's my test:

[TestMethod]
        public void register_post_saves_valid_registration()
        {
            _mockMemberRepository.Setup(r => r.GetByEmail(It.IsAny<string>())).Returns(_testMember);

        // Arrange
        RegisterViewModel model = new RegisterViewModel()
        {
            Email = "[email protected]",
            Password = "test123",
            ConfirmPassword = "test123"
        };
        // Act
        ActionResult result = _controller.Register(model);
        // Assert
        _mockMemberRepository.Verify(r => r.Register(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()), Times.Once());
        _mockMemberRepository.Verify(r => r.Save(It.IsAny<Member>()), Times.Once());
    }

This line:

_mockMemberRepository.Verify(r => r.Register(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()), Times.Once());

passes the test, but when I introduce the line below:

_mockMemberRepository.Verify(r => r.Save(It.IsAny<Member>()), Times.Once());

it fails.

Here is my Register method in my repository:

    public MembershipCreateStatus Register(string email, string password, string confirm)
    {
        if (password.Equals(confirm))
        {
            try
            {
                Member m = GetByEmail(email);
                if (m == null)
                {
                    int format = (int)PasswordFormatEnum.Encrypted;
                    string salt = GenerateSalt();
                    string pass = EncodePassword(password, format, salt);

                    m = new Member()
                    {
                        Email = email,
                        Password = pass,
                        PasswordSalt = salt,
                        PasswordFormat = format
                    };
                    Save(m);
                    return MembershipCreateStatus.Success;
                }
                else
                    return MembershipCreateStatus.DuplicateEmail;
                //"A user with that email address already exists. Please use the Forgotten Password link if you need to recover your password.";
            }
            catch (Exception ex)
            {
                _logger.LogError(ex);
                return MembershipCreateStatus.ProviderError;
            }
        }
        return MembershipCreateStatus.InvalidPassword;
    }

My Save method just takes a Member object and is a void method.

What am I doing wrong?

Upvotes: 0

Views: 802

Answers (1)

Damian Schenkelman
Damian Schenkelman

Reputation: 3545

From the above code, it seems that the Save method is part of the Register method. If that is the case, then the Register method is part of the mockRepository, so it is mocked. Thus, the real implementation, which invokes Save will never be invoked.

Assuming the above is true (which I believe is, but can't really tell because I don't have the Controller code), you need to create separate tests:

  1. The one you have right now, removing the Save verification.
  2. A unit test for the repository, and make sure that Save is invoked when Register is called.

Upvotes: 3

Related Questions