Replacing the value of Setup with Moq

c# entity-framework entity-framework-6 moq

Question

I'm mocking a DbContext and its DbSets as described here.

I'd like to create a utility method for creating my mock DbContexts, which sets up each of the context's DbSets to return an empty list by default (otherwise I get errors about null references whenever I try to query one of the DbSets). Then in unit tests where I want non-empty data in a certain DbSet, I want to call Setup again on that DbSet to supply that value than I want returned. Code is below.

I did this in a unit test and it appears to be working, but I can't find anything about how Moq handles calling Setup twice on the same property. Is doing this OK, or will it have unexpected side effects? Using the debugger, I looked into context.Setups, and calling Setup a second time on the same property adds a second object to Setups rather than overwriting the first one, which worries me.

[TestClass]
public class MyTests
{
    // Creates a new Mock<MyContext> and calls Setup on each property so
    // that they all return empty lists
    private Mock<MyContext> CreateContext()
    {
        Mock<MyContext> context = new Mock<MyContext>();

        // CreateMockDbSet is a utility method which creates a Mock<DbSet<TEntity>>
        // as described in the MSDN article listed above
        context.Setup(e => e.Customers).Returns(CreateMockDbSet<Customer>().Object);
        context.Setup(e => e.Orders).Returns(CreateMockDbSet<Order>().Object);

        return context;
    }

    [TestMethod]
    public void MyTest()
    {
        // By default, context.Customers and context.Orders will both return
        // empty DbSets
        Mock<MyContext> context = CreateContext();

        List<Order> orders = new List<Order>
        {
            new Order { Id = 1 },
            new Order { Id = 2 },
            new Order { Id = 3 }
        };

        // CreateMockDbSet creates a Mock<DbSet<Order>> which returns the orders
        // in 'orders'.  What does Moq do when I call Setup again on 'Orders'?
        context.Setup(e => e.Orders).Returns(CreateMockDbSet(orders).Object);

        // ... Do test ...
    }
}

https://msdn.microsoft.com/en-us/library/dn314429(v=vs.113).aspx

1
1
2/5/2018 2:54:03 PM

Accepted Answer

If you create a subsequent setup on a method and it's non-conditional (no constraints on the arguments) then it removes all previous setups for the method.

In your case where you don't have a method accepting arguments then you obviously can't add any constraints on them, so your subsequent setup will just replace the previous.

See this answer for an explanation of the source code.

1
2/5/2018 3:21:21 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow