MoQ:属性被正确设置为虚拟,但在非虚拟成员上仍然有无效的设置

本文关键字:设置 虚拟成员 无效 属性 MoQ 虚拟 | 更新日期: 2023-09-27 18:17:56

我想对继承自IdentityDbContext的DbContext进行单元测试

我得到一个NotSupportedException错误消息,非常常见的消息:

系统。NotSupportedException:在非虚拟(在VB中可重写)成员上设置无效

为了找到一些线索,我已经读了一堆帖子。以下是一些示例:

    这篇文章
  • 其他帖子

  • This Last one

显然,解决方案似乎是将dbSet设置为虚拟。我做了什么。

运气不好,错误仍然存在。

这是我的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();
    }
}

这是我的搜索 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; }         
}
最后这里是我的设置方法:
[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);
}

我错过了什么?

MoQ:属性被正确设置为虚拟,但在非虚拟成员上仍然有无效的设置

1)无需对DbContext进行单元测试。微软应该已经对它进行了广泛的测试。

2)如果DbContext被用作另一个类的依赖,那么抽象DbContext

public interface IDataContext {
    DbSet<Search> Searches { get; set; }
}
public class IdentityDataContext : IdentityDbContext<ApplicationUser>, IDataContext { ... }
public class SearchRepository {
    public SearchRepository(IDataContext context) { ... }
}

不要让你的类依赖于具体,而是依赖于抽象。IdentityDataContext是依赖类不需要知道的实现细节。

这样可以更灵活地测试

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