Testing Expressions With Moq

Posted almost 6 years ago on November 18, 2008

In one of the tests I was writing using Moq, I needed to test that my repository was called with a particular expression.  After struggling for a bit, I found a solution which I am sharing here in hopes that it will benefit you. 

    1         [Test]

    2         public void Then_Repository_Should_Be_Queried_For_Files_In_Pending_Status()

    3         {

    4             List<JSOFile> dummyFiles = new List<JSOFile>()

    5                       {

    6                           new JSOFile() { STATUS_CD = "P", FILE_NM = "teststring"},

    7                           new JSOFile() { STATUS_CD = "Z", FILE_NM = "test.txt"}

    8                       };

    9 

   10             _repository.Expect(x => x.FindAll(It.IsAny<Func<JSOFile, bool>>()))

   11                 .Callback((Func<JSOFile, bool> del) =>

   12                 {

   13                     dummyFiles = dummyFiles.Where(del).ToList();

   14                 });

   15 

   16             _fileManagement = new FileManagement(_repository.Object, _logger.Object, _file.Object, _jsoFileReader.Object, _jsoFileParser.Object);

   17 

   18             _fileManagement.ProcessReceivedFilesToPending();

   19 

   20             Assert.That(dummyFiles.Count == 1, "Expression passed into the FindAll method was incorrect.");

   21             Assert.That(dummyFiles.FirstOrDefault().FILE_NM == "teststring");

   22 

   23             _repository.Verify();

   24         }


What am I testing?

In the method under test (Line 18 _fileManagement.ProcessReceivedFilesToPending()), I want to ensure that my repository is being queried for the appropriate objects.  In this case, all "JSOFile" objects with the STATUS_CD of "P". 

The meat of this test method is line 10.  This line sets up an expectation that the FindAll(Func<JSOFile, bool>) method will be called from the repository object passed in via constructor (line 16, first parameter). 

(_repository defined as:)

_repository = new Moq.Mock<IRepository>();

The Expect method takes a lamba expression that allows you to set an expectation on the type being mocked.  In addition to setting expectations, you can also define callbacks.  In this example, the callback gets fired when the class under test (_fileManagement) executes the mocked object's FindAll() method.  Line 13 will receive the delegate that was passed to the _repository.FindAll.  To make sure the delegate was what I expected, I execute the delegate against a list of dummy objects.  On lines 20 and 21 I make sure that my list was narrowed down to the object with a status of "P". 

Why go to this trouble?

In the future if my repository call gets changed, this test will fail and alert the developer that they've broken intended functionality.

Comments

TrueWill writes...

I'm not sure that this will actually verify the expectation. I thought you had to add
.Verifiable()
to the Expect line, or optionally call VerifyAll() instead of Verify().

November 18, 2008

Steve Horn writes...

@truewill
Adding .Verifable() will not verify that the correct expression was passed because I am using the It.IsAny<>() method. Using Verifiable() will pass if _any_ expression with the correct signature is passed into the IRepository.

Initially I had tried to pass the expected expression to the Expect() method, and you can see the result of that here:

Stack Overflow Link

November 18, 2008

TrueWill writes...

I didn't read closely enough. So your test is really the two Asserts. If the repository method wasn't called, dummyFiles.Count would be 2.

My point was that _repository.Verify() does absolutely nothing - there's no need for that line at all. It will never fail, as no expectation is verifiable. I'd just remove it.

November 18, 2008

New Comment