views:

203

answers:

1

I'm experiencing some odd behavior in Moq - despite the fact that I setup a mock object to act a certain way, and then call the method in the exact same way in the object I'm testing, it reacts as if the method was never called.

I have the following controller action that I'm trying to test:

public ActionResult Search(string query, bool includeAll)
{
 if (query != null)
 {
  var keywords = query.Split(' ');
  return View(repo.SearchForContacts(keywords, includeAll));
 }
 else
 {
  return View();
 }
}

My unit test code:

public void SearchTestMethod() // Arrange
 var teststring = "Anders Beata";
 var keywords = teststring.Split(' ');
 var includeAll = false;
 var expectedModel = dummyContacts.Where(c => c.Id == 1 || c.Id == 2);
 repository
  .Expect(r => r.SearchForContacts(keywords, includeAll))
  .Returns(expectedModel)
  .Verifiable();

 // Act
 var result = controller.Search(teststring, includeAll) as ViewResult;

 // Assert
 repository.Verify();
 Assert.IsNotNull(result);
 AssertThat.CollectionsAreEqual<Contact>(
  expectedModel, 
  result.ViewData.Model as IEnumerable<Contact>
 );
}

where AssertThat is just a class of my own with a bunch of assertion helpers (since the Assert class can't be extended with extension methods... sigh...).

When I run the test, it fails on the repository.Verify() line, with a MoqVerificationException:

Test method MemberDatabase.Tests.Controllers.ContactsControllerTest.SearchTestMethod()
threw exception:  Moq.MockVerificationException: The following expectations were not met:
IRepository r => r.SearchForContacts(value(System.String[]), False)

If I remove repository.Verify(), the collection assert fails telling me that the model returned is null. I have debugged and checked that query != null, and that I am taken into the part of the if block where the code is run. No problems there.

Why doesn't this work?

+3  A: 

I suspect it's because the array you're passing into your mocked repository (the result of teststring.Split(' ')) is not the same object as the one that actually gets passed in from the Search method (the result of query.Split(' ')).

Try replacing the first line of your setup code with:

repository.Expect(r => r.SearchForContacts(
    It.Is<String[]>(s => s.SequenceEqual(keywords)), includeAll))

... which will compare each element of the array passed to your mock with the corresponding element in the keywords array.

Matt Hamilton
Thanks! That did the trick immeditely! =) It seems I have to read up on Moq, and specifically on when and how to use the It... constructs.
Tomas Lycken