Monday, May 28, 2012

Moq: Adding Setups/Expectations work after providing object to Dependent

First some background code.

Lets assume we have a contact repository interface like so:

public interface IContactRepository
{
    Contact Add(Contact contact);
    bool Exists(Contact contact);
}

Lets assume we also have a contact service that implements the contact repository like so:

public class ContactService
{
    IContactRepository repository;

    public ContactService() : this(new ContactRepository())
    {
    }

    public ContactService(IContactRepository repository)
    {
        this.repository = repository;
    }

    public Contact Add(Contact contact)
    {
        if (!repository.Exists(contact))
        {
            return repository.Add(contact);    
        }
        return null;
    }
}

Now I used to write the tests like this:

[TestMethod]
public void AddContactContactDoesNotExistReturnsNewContact()
{
    var mockRepository = new Mock<IContactRepository>();
    mockRepository.Setup(x => x.Exists(It.IsAny<Contact>())).Returns(false);
    mockRepository.Setup(x => x.Add(It.IsAny<Contact>())).Returns(new Contact() { Id = 1 });
    var contactService = new ContactService(mockRepository.Object);

    var result = contactService.Add(new Contact() { Name = "Test" }) as Contact;

    Assert.IsNotNull(result, "Should have returned a contact object");
    Assert.AreEqual(1, result.Id);
}

Notice how I setup the mock repository expectations prior to assigning the mock repository to the constructor of the contact service. For some reason I always though you had to define your expectations prior to assigning the mock object to its dependents.  As it turns out this is not required.  Look at the following code and notice how the setup of the expectations comes after the mock repository has been assigned to the contact service.

[TestMethod]
public void AddContactContactDoesNotExistReturnsNewContact()
{
    var mockRepository = new Mock<IContactRepository>();
    var contactService = new ContactService(mockRepository.Object);
    mockRepository.Setup(x => x.Exists(It.IsAny<Contact>())).Returns(false);
    mockRepository.Setup(x => x.Add(It.IsAny<Contact>())).Returns(new Contact() { Id = 1 });
    
    var result = contactService.Add(new Contact() { Name = "Test" }) as Contact;

    Assert.IsNotNull(result, "Should have returned a contact object");
    Assert.AreEqual(1, result.Id);
}

Knowing that there is no specific order in regards to assigning the expectations to your mock object and assigning the mock object to its dependent object can go a long way in making your code more readable.

2 comments:

  1. It doesn't work my friend you cannot return anything in an add method...

    ReplyDelete
    Replies
    1. Viktor, the above code is referencing specifically that you do not have to assign the setups to your mock object before giving the mock object to the dependent object.

      As far as returning something from the add method the interface for the contact repository is defining that a contact would be returned from the contact repository. The mock defined for the contact repository is doing just that.

      Maybe I am confused on what you mean here. More information would be helpful

      Delete