When to Specify Specific Settings in Moq

I am trying to follow this Getting Started Example for testing with Moq. I can duplicate examples in my own testing project and can get my tests to pass (testing my service in which my context is injected). However, I don't understand WHEN to use each of the following Setup calls:

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

      

Can someone explain in very simple terms when each should be used?

For example, it seems that if a method in my service that I am testing uses an expression, then I need to make a second setup call above (I did a trial and error by deleting and reinserting those calls). I've been on the Moq documentation as well as MSDN for Table-TEntity and I still don't see it. Perhaps because I don't have a strong understanding of the Linq namespace.

+3


source to share


1 answer


TL; DR . When using Entity Framework dependencies, DBContext

you will need to make these settings on whatever DBSet

you intend to mock, in particular to return bogus data in any LINQ queries on the DBSet. All 4 settings must be performed for each bullying DBSet

- this can be done in general in a helper method.

More details:

In general, with Strict mode off , installation is only required for the methods that you actually want to Mock. In this case, if you have not followed suit Setup

for a method that is called during your Unit Test, Moq will instead provide default behavior for any method that was not explicitly there Setup

, which should normally return default(T)

any expected return type, T. For classes, the value the default is null, which really won't help when testing classes that depend on Mocked EF DBContext

.

The concrete example you provided is a standard product customization for the Entity FrameworkDBSet

, which then allows you to provide bogus data for that special DbSet ( DbSet<Blog>

) by providing an alternative IQueryable<Blog>

from the collection List<Blog>

(as opposed to a typical RDBMS specific implementation).



It would be suggested to move the DBSet

mock code into the standard unit test framework / toolkit for plumbing installation to create a helper method like:

public static Mock<IDbSet<T>> GetMockedDbSet<T>(IList<T> fakeData) where T : class, new()
{
    var data = fakeData.AsQueryable();

    var mockSet = new Mock<IDbSet<T>>(); 
    mockSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(data.Provider); 
    mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(data.Expression); 
    mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(data.ElementType); 
    mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

    return mockSet;
}

      

What can you customize to your Mock DBContext

like this:

var mockContext = new Mock<IMyDbContext>();
var mockBlogDbSet = GetMockedDbSet<Blog>(new List<Blog>{... fake data here ...});
mockContext.Setup(c => c.Blogs).Returns(mockBlogDbSet.Object);

var sut = new SomeClassIWantToTest(mockContext.Object); // Inject dependency into Ctor
sut.DoSomething();...

      

+3


source







All Articles