Jonas Olesen
Jonas Olesen

Reputation: 568

Get IQueryable from Moq mockset

I have tried following the guide using Entity Framework and Moq to mock my context to test my repository.

I'm currently having problems testing my GetSingle query from my repository:

public Customer GetSingle(int id, HotelBookingContext context = null, params Expression<Func<Customer, object>>[] navigationProperties)
{
    using (var tempContext = context ?? new HotelBookingContext())
    {
        IQueryable<Customer> dbQuery = tempContext.Set<Customer>();

        foreach (Expression<Func<Customer, object>> navigationProperty in navigationProperties)
            dbQuery = dbQuery.Include(navigationProperty);

        return dbQuery
                .AsNoTracking()
                .FirstOrDefault(x => x.Id == id);
    }
}

using the following test:

public void GetSingle_QueryingASingleCustomer_ReturnsASingleCustomer()
{
    var cus = new Customer() { Email = "testMail", Name = "testName", Id = 1 };
    var customer = new List<Customer> {cus}.AsQueryable();

    var mockSet = new Mock<DbSet<Customer>>();
    mockSet.As<IQueryable<Customer>>().Setup(m => m.Provider).Returns(customer.Provider);
    mockSet.As<IQueryable<Customer>>().Setup(m => m.Expression).Returns(customer.Expression);
    mockSet.As<IQueryable<Customer>>().Setup(m => m.ElementType).Returns(customer.ElementType);
    mockSet.As<IQueryable<Customer>>().Setup(m => m.GetEnumerator()).Returns(customer.GetEnumerator());

    var mockContext = new Mock<HotelBookingContext>();
    mockContext.Setup(m => m.Customers).Returns(mockSet.Object);

    var temp = _customerRepository.GetSingle(cus.Id, mockContext.Object);
    Assert.AreEqual(temp.Name, cus.Name);
    Assert.AreEqual(temp.Email, cus.Email);
    Assert.AreEqual(temp.Id, cus.Id);
}

If I debug the code I notice that in the GetSingle function the IQueryable called dbQuery remains null and can therefore not be used in the return statement.

Why is this?

However, if I run it with a real context it works fine.

Upvotes: 1

Views: 1495

Answers (1)

Nkosi
Nkosi

Reputation: 247413

That is because in the setup you setup .Customers property on the mocked context and not the .Set<Customer>() function. Moq has no clue what to do with that based on the current setup.

mockContext.Setup(m => m.Set<Customer>()).Returns(mockSet.Object);

The above setup should now match the expected behavior of the method under test in its current format.

Other wise if this is the setup...

mockContext.Setup(m => m.Customers).Returns(mockSet.Object);

...then you need to update the method under test to ...

IQueryable<Customer> dbQuery = tempContext.Customers;

for the test to exercise as expected.

Upvotes: 1

Related Questions