Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moq & EF6 - Mocking EF6 Remove method not removing an object

I am trying to mock my EF6 DbContext and it all works for Add, Update, Find methods. But it's not working for Remove method for unknown reason.

In theory, after removing, the Students collection should have only 1 return left. But it keeps returning the Count - 2.

I put 3 Moq.Verify checks to ensure that all methods are called and they are executed indeed. But it's not actually removing the item from the Students Collection.

If I commented Assert.Equal line which check the counts, the whole test passed.

Delete XUnit Method

[Fact]
public void Delete()
{            
    Mock<DbContexts.MVCWebAppDbContext> dbContext = new Mock<DbContexts.MVCWebAppDbContext>();
    IStudentsService studentService = new StudentsService(dbContext.Object);

    var students = new List<Student>()
    {
        new Student() { StudentID = 1, RefNo = "12456343", FirstName = "John", LastName = "Smith", DateOfBirth = DateTime.Now.AddYears(-10), DateCreated = DateTime.Now },
        new Student() { StudentID = 2, RefNo = "87984564", FirstName = "Pete", LastName = "Luck", DateOfBirth = DateTime.Now.AddYears(-20), DateCreated = DateTime.Now.AddDays(1) }
    };

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

    mockSet.Setup(m => m.Remove(It.IsAny<Student>())).Callback<Student>((entity) => students.Remove(entity));

    dbContext.Setup(c => c.Students).Returns(mockSet.Object);

    int idToDelete = 1;

    dbContext.Setup(s => s.Students.Find(idToDelete)).Returns(students.Single(s => s.StudentID == idToDelete));

    // call delete method now
    studentService.Delete(idToDelete);

    // 1 object deleted, it should return 1
    Assert.Equal(1, students.Count());  // <----- Error here

    dbContext.Verify(s => s.Students.Find(idToDelete), Times.Once);
    dbContext.Verify(s => s.Students.Remove(It.IsAny<Student>()), Times.Once);
    dbContext.Verify(s => s.SaveChanges(), Times.Once);
}

StudentService.cs Delete method

MVCWebAppDbContext _context;

public StudentsService(MVCWebAppDbContext context)
{
    _context = context;
}

public int Delete(int id)
{
    var objToDelete = _context.Students.Find(id);

    if (objToDelete != null)
    {
        _context.Students.Remove(objToDelete);
        return _context.SaveChanges();
    }

    return -1;
}

Could you guys please help me with this Remove method mocking?

like image 714
TTCG Avatar asked Apr 14 '17 20:04

TTCG


People also ask

What is EOQ vs Moq?

vs E.O.Q.? M.O.Q. is the minimum order quantity for profit, which may be used either by a business or manufacturer, while the E.O.Q., or economic order quantity, is the ideal level of inventory to be purchased and stocked to avoid extraneous inventory and storage costs.

What is Moq pricing?

MOQ stands for minimum order quantity and is the minimum amount of product a seller, supplier, or manufacturer requires a customer to purchase based on units or price. For example, one supplier might set an MOQ of 100 units, while another might require an MOQ price of $1,000+ on purchase orders.

What does min order mean?

minimum order in Retail A minimum order is the smallest amount or number that may be ordered in one delivery, usually to spread delivery costs over an economical number of units. There is no minimum order and all of our wholesale offerings are sold in small pack sizes, with delivery charged at cost only.

What is shipping Moq?

The minimum order quantity (MOQ) is the smallest order size suppliers will accept when you order goods from them. It can be expressed as a quantity, although some suppliers work with a minimum order value.


1 Answers

replace

mockSet
    .Setup(m => m.Remove(It.IsAny<Student>()))
    .Callback<Student>((entity) => students.Remove(entity));

with

dbContext
    .Setup(m => m.Students.Remove(It.IsAny<Student>()))
    .Callback<Student>((entity) => students.Remove(entity));

Most of the setup was done using the DbContext.Students which overrides the setup on DbSet.Remove

In fact you can actually remove all the DbSet mocking and test would still pass

[Fact]
public void Delete() {
    var dbContext = new Mock<DbContexts.MVCWebAppDbContext>();
    IStudentsService studentService = new StudentsService(dbContext.Object);

    var students = new List<Student>()
    {
        new Student() { StudentID = 1, RefNo = "12456343", FirstName = "John", LastName = "Smith", DateOfBirth = DateTime.Now.AddYears(-10), DateCreated = DateTime.Now },
        new Student() { StudentID = 2, RefNo = "87984564", FirstName = "Pete", LastName = "Luck", DateOfBirth = DateTime.Now.AddYears(-20), DateCreated = DateTime.Now.AddDays(1) }
    };

    dbContext
        .Setup(m => m.Students.Remove(It.IsAny<Student>()))
        .Callback<Student>((entity) => students.Remove(entity));

    int idToDelete = 1;

    dbContext
        .Setup(s => s.Students.Find(idToDelete))
        .Returns(students.Single(s => s.StudentID == idToDelete));

    // call delete method now
    studentService.Delete(idToDelete);

    // 1 object deleted, it should return 1
    Assert.AreEqual(1, students.Count());

    dbContext.Verify(s => s.Students.Find(idToDelete), Times.Once);
    dbContext.Verify(s => s.Students.Remove(It.IsAny<Student>()), Times.Once);
    dbContext.Verify(s => s.SaveChanges(), Times.Once);
}
like image 193
Nkosi Avatar answered Sep 29 '22 17:09

Nkosi