使用Moq和DBSet时的空表达式和提供程序<t>

时间:2017-04-27 13:50:38

标签: c# .net unit-testing entity-framework-6 moq

我好几天都陷入了一个非常奇怪的问题,无法找到解决方案。我正在嘲笑DatabaseContext和一些DBSet<T>实体。创建moq工作正常,看起来很好。 在特殊.Any()上调用DBSet时,它会与NullReferenceException崩溃。我仔细看了一下,发现我的模拟DBSet的表达式和提供者再次为空。但我不明白为什么。

创建DB-Set的函数:

private DbSet<T> GetQueryableMockDbSet<T>() where T : class
{
    var list = mockListCollection.Single(o => o.GetType().GetGenericArguments()[0] == typeof (T))
        .ToList()
        .ConvertAll(o => (T) o);

    var queryable = list.AsQueryable();

    var dbSet = new Mock<DbSet<T>>();
    dbSet.As<IQueryable<T>>()
        .Setup(m => m.Provider)
        .Returns(new TestDbAsyncQueryProvider<T>(queryable.Provider));

    //dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
    dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
    dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
    dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator());
    dbSet.Setup(d => d.Add(It.IsAny<T>())).Callback<T>(list.Add);

    dbSet.Object.AddRange(list);

    return dbSet.Object;
}

我的DatabaseContext

的每个表都会调用它
private void InitMockMethods<T>() where T : class, new()
{
    this.DataBaseContextMock.Setup(m => m.Set<T>()).Returns(this.GetQueryableMockDbSet<T>());
    this.DataBaseContextMock.Setup(m => m.Set<T>().Local).Returns(new ObservableCollection<T>(this.GetQueryableMockDbSet<T>()));

    this.DataBaseContextMock.Setup(m => m.Set<T>().Create()).Returns(new T());

    // first get the parameter name out of database context by generic type argument (e. g. DbSet<TblProject>  --> get name by TblProject)
    // because type and typename are not equal.
    // TblProject --> Name is TblProjects
    var paramName = typeof (IDatabaseContext).GetProperties().Single(o => o.CanWrite && o.PropertyType.GetGenericArguments()[0] == typeof(T)).Name;

    // build lamda expression for moq setup
    var parameter = Expression.Parameter(typeof(IDatabaseContext));
    var body = Expression.PropertyOrField(parameter, paramName);
    var lambdaExpression = Expression.Lambda<Func<IDatabaseContext, object>>(body, parameter);

    // setup moq
    this.DataBaseContextMock.Setup(lambdaExpression).Returns((DbSet<T>)this.GetQueryableMockDbSet<T>());
}

之后,所有对象看起来都很好。但是当我调用DatabaseContext.Set<TblVendor>().Any()时,它会因为Provider和Expression为空而崩溃。

有人在那里,谁知道,哪些可能是错的?!

编辑: 这是测试功能:

[Test]
    [TestCase(11,31)]
    public void TestFilterExtension(int expGl1, int expGl2)
    {
        var userMock = new Mock<AspNetUser>();
        userMock.Setup(x => x.EnableFilterByUserAuthorization).Returns(true);
        userMock.Setup(x => x.Tablename).Returns("TblVendor");
        userMock.Setup(x => x.Columnname).Returns("gl");
        userMock.Setup(x => x.Value).Returns(expGl1.ToString);

        var gl = new Mock<TblVendor>();
        gl.Setup(n => n.Id).Returns(Guid.NewGuid);
        gl.Setup(x => x.GL).Returns(expGl1);

        var gl2 = new Mock<TblVendor>();
        gl2.Setup(n => n.Id).Returns(Guid.NewGuid);
        gl2.Setup(x => x.GL).Returns(expGl2);

        var manager = new VendorManager(base.Manager, MockProvider.Instance.DataBaseContextMock.Object,
            userMock.Object, MockProvider.Instance.EntityHelperMock.Object);

        //MockProvider.Instance.ClearMockList<TblVendor>();

        //manager.AddOrUpdate(gl.Object);
        //manager.AddOrUpdate(gl2.Object);

        var test = MockProvider.Instance.DataBaseContextMock.Object.Set<TblVendor>();
        var b = test.Any(); // <----- NullReferenceException because of missing Provider and or Expression
        //var b = manager.EntityCollection;
        //var data = manager.EntityCollection.ToList();

    }

1 个答案:

答案 0 :(得分:0)

我发现你已经使用了异步提供程序方式,所以我会告诉你尝试实现getenumerator异步,如msdn指南中所述,如何模拟ef dbcontext。

完成后,请避免使用moq查询,因为不需要。您的模拟已经按预期使用linq查询!此外,如果有另一个函数调用为Include(),你必须模拟它以返回你想要的itrm(大多数时候将是原始对象mock,原始列表)