C# Moq-模拟复杂存储库方法-未返回列表对象

C# Moq-模拟复杂存储库方法-未返回列表对象,c#,entity-framework,moq,C#,Entity Framework,Moq,我使用的是实体框架,有一个通用的存储库方法,允许我查询DbSet,还包括导航属性。我试图为使用这段代码的一些代码编写一个单元测试,我需要模拟它进行单元测试。我正在使用最小起订量 这是repository方法——它允许我使用表达式进行查询,还包括我想要的相关导航属性。我在Julie Lerman在Pluralsight企业课程中的EF中看到了这种模式 public IEnumerable<TEntity> FindByInclude(Expression<Func<TEnt

我使用的是实体框架,有一个通用的存储库方法,允许我查询
DbSet
,还包括导航属性。我试图为使用这段代码的一些代码编写一个单元测试,我需要模拟它进行单元测试。我正在使用最小起订量

这是repository方法——它允许我使用表达式进行查询,还包括我想要的相关导航属性。我在Julie Lerman在Pluralsight企业课程中的EF中看到了这种模式

public IEnumerable<TEntity> FindByInclude(Expression<Func<TEntity, bool>> predicate,
                                            params Expression<Func<TEntity, object>>[] includeProperties)
{
    var query = GetAllIncluding(includeProperties);
    IEnumerable<TEntity> results = query.Where(predicate).ToList();
    return results;
}

private IQueryable<TEntity> GetAllIncluding(params Expression<Func<TEntity, object>>[] includeProperties)
{
    IQueryable<TEntity> queryable = DbSet.AsNoTracking();

    return includeProperties.Aggregate
      (queryable, (current, includeProperty) => current.Include(includeProperty));
}
因此,此查询将根据我传入的id以及相关的
LocationRooms
Staff
集合,返回单个
位置
实体

如何为
FindByInclude
方法设置最小起订量?以下是我的单元测试模拟设置:

var mockLocationRepository = new Mock<ILocationRepository>();
var location = new Location {Id = 1,Name = "LocationName", LocationRooms = new List<LocationRoom>(), Staff = new List<Staff>()};
mockLocationRepository.Setup(r => r.FindByInclude(l => l.Id == It.IsAny<int>(), l => l.LocationRooms, l => l.Staff))
            .Returns(() => new List<Location> { location });
var mockLocationRepository=new Mock();
var location=new location{Id=1,Name=“LocationName”,LocationRooms=new List(),Staff=new List()};
mockLocationRepository.Setup(r=>r.FindByInclude(l=>l.Id==It.IsAny(),l=>l.LocationRooms,l=>l.Staff))
.Returns(()=>新列表{location});
从这里显示的Moq设置代码-我想我应该得到一个包含1个位置的列表-我指定的Id为1的位置对象。但是,当我运行单元测试并点击此代码时,
FindByInclude
的设置方法返回一个空列表。因此,当
DeleteLocation
方法中的代码被命中并且调用Single()方法时,我得到一个错误,即“元素不包含序列”


我认为问题在于我对
FindByInclude
方法的Moq设置语法有问题,但不确定是什么问题。

注释太长,因此添加作为答案

这是表达方式。首先尝试一个更通用的表达式设置,看看它是否有效

var location = new Location {
    Id = 1,
    Name = "LocationName", 
    LocationRooms = new List<LocationRoom>(), 
    Staff = new List<Staff>()
};
mockLocationRepository
    .Setup(m => m.FindByInclude(It.IsAny<Expression<Func<TEntity, bool>>>(), It.IsAny<Expression<Func<TEntity, object>>[]>())
    .Returns(() => new List<Location> { location });
var位置=新位置{
Id=1,
Name=“LocationName”,
LocationRooms=新列表(),
职员=新名单()
};
mockLocationRepository
.Setup(m=>m.FindByInclude(It.IsAny(),It.IsAny())
.Returns(()=>新列表{location});

作为@Nkosi答案的替代方案,你不使用Moq,而是自己实现一个
ILocationRepository
的存根实现,这样做的想法是,如果模仿变得很难,也许你不应该这样做

公共类StubLocationRepository:ILocationRepository
{
私有只读IEnumerable\u findByInclude;
公共StubLocationRepository(IEnumerable findByInclude)
{
_findByInclude=findByInclude;
}
公共IEnumerable FindByInclude(
表达式谓词,
参数表达式[]includeProperties)
{
返回_findByInclude;
}
}
这太简单了,因为它假设您只有一个方法。如果您有很多方法,并且不想为每个方法传递常量值,那么您可以让存根的
ctor
接受可选参数,以便只存根所需的方法

此外,由于
ILocationRepository
很可能继承自通用接口,因此您可以使用一个通用存根实现,将其子类化以构建特定存根,即实现
ILocationRepository
定义的方法

var location = new Location {
    Id = 1,
    Name = "LocationName", 
    LocationRooms = new List<LocationRoom>(), 
    Staff = new List<Staff>()
};
mockLocationRepository
    .Setup(m => m.FindByInclude(It.IsAny<Expression<Func<TEntity, bool>>>(), It.IsAny<Expression<Func<TEntity, object>>[]>())
    .Returns(() => new List<Location> { location });