Reputation: 155
I'm trying to mock Entity Frameworks DbContext using Moq and in particular its extension methods Add(), Tolist() and Find().
I need the Find() and ToList() methods to actually return values stored in my mockContext.Object
.
I've created my DbSet and set following properties:
var mockTickets = new Mock<DbSet<Ticket>>();
mockTickets.As<IQueryable<Ticket>>().Setup(m => m.Provider).Returns(tickets.Provider);
mockTickets.As<IQueryable<Ticket>>().Setup(m => m.Expression).Returns(tickets.Expression);
mockTickets.As<IQueryable<Ticket>>().Setup(m => m.ElementType).Returns(tickets.ElementType);
mockTickets.As<IQueryable<Ticket>>().Setup(m => m.GetEnumerator()).Returns(() => tickets.GetEnumerator());
I've created my DbContext with the following property
var mockContext = new Mock<SupportCenterDbContext>();
mockContext.Setup(m => m.Tickets).Returns(mockTickets.Object);
Now I'm trying to test the following methods
mockContext.Object.Tickets.Add(Ticket ticket)
mockContext.Object.Tickets.ToList<Ticket>()
mockContext.Object.Tickets.Find(int ticketNumber)
I've tried the following code but get "Invalid setup on an extension method".
mockContext.Setup(x => x.Tickets.Add(It.IsAny<Ticket>())).Returns(It.IsAny<Ticket>());
mockContext.Setup(x => x.Tickets.ToList()).Returns(mockTickets.Object.ToList());
mockContext.Setup(x => x.Tickets.Find(It.IsAny<int>())).Returns(It.IsAny<Ticket>());
These are my assertions for the Add()
and ToList()
methods
//ToList
Assert.AreEqual(result.Count(), mockContext.Object.Tickets.Count());
Assert.IsInstanceOfType(result, typeof(IEnumerable<Ticket>));
//Add
Assert.IsInstanceOfType(result, typeof(Ticket));
mockContext.Verify(x => x.Tickets.Add(It.IsAny<Ticket>()), Times.Once());
mockContext.Verify(x => x.SaveChanges(), Times.Once());
EDIT
I'm a step closer by removing mockContext.Setup(x => x.Tickets.ToList()).Returns(mockTickets.Object.ToList());
.
and adding the following
mockContext.Setup(x => x.Tickets.Add(It.IsAny<Ticket>())).Returns<Ticket>(x => x);
mockContext.Setup(t => t.Tickets.Find(It.IsAny<int>())).Returns<int>(x => mockContext.Object.Tickets.Find(x));
This last line still doesn't produce the desired output. Is it not possible to pass the value of the input parameter to the Find()
method in the Returns()
section?
Thanks in advance for any help.
Upvotes: 3
Views: 4423
Reputation: 2252
You can't mock extension methods, and it is not a common practice to mock the DBContext.
A better idea would be to use an in-memory data context and populate it with test data, as described here: https://learn.microsoft.com/en-us/ef/core/miscellaneous/testing/in-memory
Upvotes: 2