4

I'd like to unit test a DbContext which inherits from IdentityDbContext

I am getting a NotSupportedException error message with the very common message :

System.NotSupportedException: Invalid setup on a non-virtual (overridable in VB) member

To find some clues I already read a bunch of posts. Here are some samples:

Obviously, the solution appears to set the dbSet as virtual. What I've done.

Bad luck, the error remains.

Here is my IdentityDataContext :

public class IdentityDataContext : IdentityDbContext<ApplicationUser>
{      
    public virtual DbSet<Search> Searches { get; set; }

    public IdentityDataContext()
        : base("LocalDb",
              throwIfV1Schema: true)
    {            
    }

    public static IdentityDataContext Create()
    {
        return new IdentityDataContext();
    }
}

Here is my Search POCO :

public class Search : BaseEntity
{
    //BaseEntity is just an abstract class with createdAt,Id,updatedAt property
    public string ConsumerIdentifier { get; set; }
    public string LanguageCode { get; set; }         
}

Finally here is my Set Up Method :

[TestInitialize]
public void SetupTest()
{
    //DataInitializer.GetAllSearches() returns a List of "Search"

    _searches = DataInitializer.GetAllSearches();

    var dbSet = new Mock<DbSet<Search>>();
    dbSet.As<IQueryable<Search>>().Setup(m => m.Provider).Returns(_searches.AsQueryable().Provider);
    dbSet.As<IQueryable<Search>>().Setup(m => m.Expression).Returns(_searches.AsQueryable().Expression);
    dbSet.As<IQueryable<Search>>().Setup(m => m.ElementType).Returns(_searches.AsQueryable().ElementType);
    dbSet.As<IQueryable<Search>>().Setup(m => m.GetEnumerator()).Returns(_searches.AsQueryable().GetEnumerator());
    dbSet.Setup(d => d.Add(It.IsAny<Search>())).Callback<Search>(_searches.Add);

    _dataContextMock = new Mock<IdentityDataContext>()
    {
        CallBase = true
    };

    // The error appears here ---------------- _
    dataContextMock.Setup(x   => x.Searches).Returns(dbSet.Object);
    //----------------------------------------------------------------------

    _dataContextMock.Setup(x => x.Set<Search>()).Returns(dbSet.Object);

    _searchRepository = new SearchRepository(_dataContextMock.Object);
}

What am I missing?

Community
  • 1
  • 1
BertrandD
  • 43
  • 3

1 Answers1

0

1) no need to unit test DbContext. Microsoft would have done extensive testing on it already.

2) if the DbContext is to be used as a dependency for another class then abstract the dbcontext

public interface IDataContext {
    DbSet<Search> Searches { get; set; }
}

public class IdentityDataContext : IdentityDbContext<ApplicationUser>, IDataContext { ... }

public class SearchRepository {
    public SearchRepository(IDataContext context) { ... }
}

Don't have you classes depending on concretions but rather on abstractions. IdentityDataContext is an implementation detail that dependent classes need not know about.

This would then allow more flexibility for testing

Mock<IDataContext> _dataContextMock;

[TestInitialize]
public void SetupTest() {

    //DataInitializer.GetAllSearches() returns a List of "Search"
    _searches = DataInitializer.GetAllSearches();
    var queryable = _searches.AsQueryable();

    var dbSet = new Mock<DbSet<Search>>();
    dbSet.As<IQueryable<Search>>().Setup(m => m.Provider).Returns(queryable.Provider);
    dbSet.As<IQueryable<Search>>().Setup(m => m.Expression).Returns(queryable.Expression);
    dbSet.As<IQueryable<Search>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
    dbSet.As<IQueryable<Search>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator());
    dbSet.Setup(d => d.Add(It.IsAny<Search>())).Callback<Search>(_searches.Add);


    _dataContextMock = new Mock<IDataContext>();

    _dataContextMock.Setup(x => x.Searches).Returns(dbSet.Object);

    _dataContextMock.Setup(x => x.Set<Search>()).Returns(dbSet.Object);

    _searchRepository = new SearchRepository(_dataContextMock.Object);

}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • Thanks for this. That's an approach I hadn't thought about. I read this [article](https://msdn.microsoft.com/en-us/library/dn314429(v=vs.113).aspx#Anchor_7) on MSDN. I'm wondering why this other approach could not work in my case ? Basically, they use a Service while I implement repository and unit of work design patterns . But those have the same purpose : managing models. Am I wrong ? – BertrandD Nov 15 '16 at 20:42