1

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;
    }
Community
  • 1
  • 1
lloydphillips
  • 2,775
  • 2
  • 33
  • 58
  • 1
    You are mocking the object that you are trying to test. You should instantiate a concrete repository. – Damian Schenkelman Nov 09 '12 at 02:47
  • Saw this post http://stackoverflow.com/questions/1417048/how-to-verify-another-method-in-the-class-was-called-using-moq?rq=1 and was wondering if I might be best pushing in a Service layer which would contain the register method and code and having a seperate Data layer containing the Save method. Would that get around the issue? Is that what the problem I have is? – lloydphillips Nov 09 '12 at 02:47
  • Is your repository even mockable? i.e. is it abstract? – Mike Parkhill Nov 09 '12 at 03:00
  • Yes, I've defined an interface. – lloydphillips Nov 09 '12 at 03:15

1 Answers1

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.

Mike Parkhill
  • 5,511
  • 1
  • 28
  • 38