How to verify that method argument's property values are set when mocking methods with Moq?

StackOverflow https://stackoverflow.com/questions/1803433

  •  05-07-2019
  •  | 
  •  

Question

Not sure if it has been asked before, here is the question.

Code first:

    public class Customer {
        public string Password { get; set; }
        public string PasswordHash { get; set; }
    }
    public class CustomerService {
        private ICustomerRepository _repo;

        public CustomerService(ICustomerRepository repo) {
            _repo = repo;
        }

        public int? AddCustomer(Customer customer) {
            customer.PasswordHash = SHA1Hasher.ComputeHash(customer.Password);
            return _repo.Add(customer);
        }
    }

    public interface ICustomerRepository {
        int? Add(Customer c);
    }
    public class CustomerRepository : ICustomerRepository {
        int? AddCustomer(Customer customer) {
            // call db and return identity
            return 1;
        }
    }

    [TestClass]
    public class CustomerServiceTest {
        [TestMethod]
        public void Add_Should_Compute_Password_Hash_Before_Saving() {
            var repoMock = new Mock<ICustomerRepository>();
            //how do I make sure the password hash was calculated before       passing the customer to repository???
        }
    }

How do I verify that CustomerService assigned the PasswordHash before passing the customer to repository?

Was it helpful?

Solution

There are several approaches you could take. Although not necessarily the best solution, here's one that doesn't require you to change your existing API. It assumes that SHA1Hasher.ComputeHash is a public method.

[TestClass]
public class CustomerServiceTest
{
    [TestMethod]
    public void Add_Should_Compute_Password_Hash_Before_Saving()
    {
        var customer = new Customer { Password = "Foo" };
        var expectedHash = SHA1Hasher.ComputeHash(customer.Password);

        var repoMock = new Mock<ICustomerRepository>();
        repoMock
            .Setup(r => r.Add(It.Is<Customer>(c => c.PasswordHash == expectedHash)))
            .Returns(1)
            .Verifiable();

        // invoke service with customer and repoMock.Object here...

        repoMock.Verify();
    }
}

A slightly better solution would be to turn the SHA1Hasher into an injected service (such as IHasher) so that you can confirm that the PasswordHash property was assigned the value created by the IHasher instance.

Opening op your API even more, you could make the PasswordHash property virtual, so that you could pass a Mock Customer to the AddCustomer method to verify that the property was correctly set.

OTHER TIPS

You could make SHA1Hasher non-static and virtual or wrap it in a ISHA1Hasher interface which can then be mocked. Wrapping static methods and objects in mockable classes is a classic way to increase testability.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top