Search code examples
c#.netunit-testingmoqverify

Verify method has been called with IEnumerable containing 'x' elements with Moq


I have a repository with an Add method that takes an IEnumerable as parameter:

public void Add<T>(T item) where T : class, new(){}

In a unittest I want to verify that this method is called with an IEnumerable that contains exactly the same amount of elements as another IEnumerable

[Test]
public void InvoicesAreGeneratedForAllStudents()
{
    var students = StudentStub.GetStudents();
    session.Setup(x => x.All<Student>()).Returns(students.AsQueryable());

    service.GenerateInvoices(Payments.Jaar, DateTime.Now); 

    session.Verify(x => x.Add(It.Is<IEnumerable<Invoice>>(
        invoices => invoices.Count() == students.Count())));
 }

Result of the unit test:

Moq.MockException : 
Expected invocation on the mock at least once, but was never performed: 

x => x.Add<Invoice>(It.Is<IEnumerable`1>(i => i.Count<Invoice>() == 10))

No setups configured.

What am I doing wrong?


Solution

  • From your code example you haven't set up the x => x.Add on the Moq

    session.Setup(x => x.Add(It.IsAny<IEnumerable>());
    

    Unless the Setup for x.All is meant to be x.Add? If so, you need to match the Verify and Setup exactly - a good way to do that is to extract it to a common method that returns an Expression.

    EDIT: Added a sample, I have changed the signature of Add as I can't see how you could pass a collection otherwise.

    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            Mock<Boo> moqBoo = new Mock<Boo>();
            moqBoo.Setup(IEnumerableHasExpectedNumberOfElements(10));
    
            // ACT
    
            moqBoo.Verify(IEnumerableHasExpectedNumberOfElements(10));
        }
    
        private static Expression<Action<Boo>> IEnumerableHasExpectedNumberOfElements(int expectedNumberOfElements)
        {
            return b => b.Add(It.Is<IEnumerable<Invoice>>(ie => ie.Count() == expectedNumberOfElements));
        }
    }
    
    public class Boo
    {
        public void Add<T>(IEnumerable<T> item) where T : class, new()
        {
        }
    }
    
    public class Invoice
    {
    
    }
    

    Also, a good way to debug these things is to set your Mock up with MockBehavior.Strict and then you'll be informed by the invoked code what you need to configure.