BertrandD
BertrandD

Reputation: 43

MoQ : Property is correctly set as virtual but still have invalid setup on a non-virtual member

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?

Upvotes: 4

Views: 980

Answers (1)

Nkosi
Nkosi

Reputation: 247551

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);

}

Upvotes: 0

Related Questions