0
votes

I'm trying to mock my DbContext class to do unit tests with NSubstitute but I cannot recover this data from my fake dbcontext through the repository class.

I have a generic class (SubstituteDbContext) to create sobe DbSet's and set them to the respective DbSet property in my DbContext.

I have the code below for each property in DbContext that I want to mock:

var data = DbSetData.MyData();
var dbSet = SubstituteDbContext.DbSet(data);
dbContext.MyObject.Returns(dbSet);

I create a DbSet to every property with the method below:

public static DbSet<T> getDbSet<T>(IEnumerable<T> data = null)
    where T : class
{
    var dbSet = Substitute.For<DbSet<T>, IQueryable<T>>();

    if (data != null)
    {
        var queryable = data.AsQueryable();
        ((IQueryable<T>)dbSet).Provider.Returns(queryable.Provider);
        ((IQueryable<T>)dbSet).Expression.Returns(queryable.Expression);
        ((IQueryable<T>)dbSet).ElementType.Returns(queryable.ElementType);
        ((IQueryable<T>)dbSet).GetEnumerator().Returns(queryable.GetEnumerator());
        ((IQueryable<T>)dbSet).AsNoTracking().Returns(queryable);
    }
    return dbSet;
}

And in my BaseRepository class (my abstract-parent class for every repository) I have some methods like below to get data:

public virtual IEnumerable<T> List(Expression<Func<T, bool>> predicate)
{
    return DbContext.Set<T>()
        .Where(predicate)
        .AsEnumerable();
}

But when my debugger runs the List method of BaseRepository I have two possible results (because I tried some variations of the code above):

1º I've got System.NotImplementedException
2º The result returned is empty (but 
2

2 Answers

2
votes

Your SUT invokes DbContext.Set<T>() however you only set up dbContext.MyObject.Returns(dbSet). You'll need to set up the former.

0
votes

Like @rgvlee said I wasn't setting up DbSet correctly.

I've changed my getDbSet<T> generic method for setDbSet<T> because I'm not returning the mocked DbSet anymore and setting it im DbContext in my another generic method with SetValue (from reflection).

Now I'm setting up the generic Set<T> property from my mocked DbContext directly in setDbSet<T> method and isn't necessary to set it directly with reflection.

Below the code from the new setDbSet<T>() (that was getDbSet<T>()):

public static void setDbSet<T>(DbContext dbContext, IEnumerable<T> data = null)
    where T : class
{
    var dbSet = Substitute.For<DbSet<T>, IQueryable<T>>();

    if (data != null)
    {
        var queryable = data.AsQueryable();
        ((IQueryable<T>)dbSet).Provider.Returns(queryable.Provider);
        ((IQueryable<T>)dbSet).Expression.Returns(queryable.Expression);
        ((IQueryable<T>)dbSet).ElementType.Returns(queryable.ElementType);
        ((IQueryable<T>)dbSet).GetEnumerator().Returns(queryable.GetEnumerator());
        ((IQueryable<T>)dbSet).AsNoTracking().Returns(queryable);
    }

    dbContext.Set<T>().Returns(dbSet);
}

And In my generic method that calls setDbSet<T>() I've removed the line below where I was setting up that mocked dbSet returned from getDbSet<T>() in my DbContext.

propertyInfo.SetValue(dbContext, dbSet);