Using moq to verify a method is called in a repository

大憨熊 提交于 2019-12-11 11:26:02

问题


I asked this question earlier about testing a controller action and verifying that a method in my repository was being called. The answer came back that I should be testing a Save method which is called inside the Register method (both in the same repository) in a seperate test on the repository only. That's what I thought, but I'm coming to do the test and I can't get it to work. :(

Here's the repository test, where am I going wrong?

    [TestMethod]
    public void Register_calls_Save_method_when_Member_is_valid()
    {
        _mockMemberRepository.Setup(r => r.GetByEmail(It.IsAny<string>())).Returns((Member)null);            
        MembershipCreateStatus status = _mockMemberRepository.Object.Register(_testMember.Email, "password", "password");
        _mockMemberRepository.Verify(r => r.Save(It.IsAny<Member>()), Times.Once());
    }

Here's the Register method on the 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;
    }

回答1:


You can't use Moq to verify that you're calling one method on an object from another method on that object. What you can do is verify that something that is called in your Save() method is called.

For example, if I was writing my own repository that was using Ado.Net to update a database I could do something like the following:

public class MyRepository : IRepository {
   private readonly IDatabase m_db;
   public MyRepository(IDatabase myDatabase){
      m_db = myDatabase;
   }

   public void Register(string email, string password, etc.){
      // ... do stuff ...
      Save(m);
      // ... do stuff ...
   }

   public void Save(Member member){
      // ... build sql query ...
      m_db.ExecuteNonQuery(sqlCommand);

   }
}

You'd then pass a mocked database object to your repository in your test and you'd verify that:

[TestMethod]
public void Register_calls_Save_method_when_Member_is_valid()
{
    Mock<IDatabase> _mockDB = new Mock<IDatabase>();
    // Setup mockDB with return values for GetByEmail(), etc.

    _repository = new MyRepository(_mockDB.Object);

    MembershipCreateStatus status = _repository.Register("Email@Email.com", "password", "password");
    _mockDB.Verify(r => r.ExecuteNonQuery(It.IsAny<SqlCommand>()), Times.Once());
}

So, you're not verifying that Save() is called explicitly, but by verifying that the right underlying database call was called you can verify that Save() happened.

The same approach should work for other frameworks too.



来源:https://stackoverflow.com/questions/13301351/using-moq-to-verify-a-method-is-called-in-a-repository

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!