Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何模拟多个级别的DbSet。包括lambda?_C#_Entity Framework_Unit Testing_Mocking_Moq - Fatal编程技术网

C# 如何模拟多个级别的DbSet。包括lambda?

C# 如何模拟多个级别的DbSet。包括lambda?,c#,entity-framework,unit-testing,mocking,moq,C#,Entity Framework,Unit Testing,Mocking,Moq,我正在使用Moq编写单元测试,这些测试使用实体框架6DbSet和DbContext对象。我有一个带有级联/多级Include的服务方法,我不知道如何设置它进行测试。服务方法如下所示: return DataContext.Cars .Include(p => p.Model) .Include(p => p.Model.Make) .Select(c => new { Key = c.CarId,

我正在使用Moq编写单元测试,这些测试使用实体框架6
DbSet
DbContext
对象。我有一个带有级联/多级
Include
的服务方法,我不知道如何设置它进行测试。服务方法如下所示:

return DataContext.Cars
    .Include(p => p.Model)
    .Include(p => p.Model.Make)
    .Select(c => new 
         {
             Key = c.CarId, 
             Value = string.Format("{0} {1} {2}", c.Model.Make.Name, c.Model.Name, c.Trim)
         }
    ).ToArray();
mockCarDbSet.Setup(m => m.Include(It.IsAny<string>())).Returns(mockCarSet.Object);
我知道我必须设置
Include
以返回模拟对象,如下所示:

return DataContext.Cars
    .Include(p => p.Model)
    .Include(p => p.Model.Make)
    .Select(c => new 
         {
             Key = c.CarId, 
             Value = string.Format("{0} {1} {2}", c.Model.Make.Name, c.Model.Name, c.Trim)
         }
    ).ToArray();
mockCarDbSet.Setup(m => m.Include(It.IsAny<string>())).Returns(mockCarSet.Object);
mockCarDbSet.Setup(m=>m.Include(It.IsAny()).Returns(mockCarSet.Object);
但是我从级联的
.Include(p=>p.Model.Make)
中得到了一个空引用异常。如何设置Moq来处理多个级别的
包含

编辑
好的,结果是我不能使用
it。对于
Include
调用,使用lambdas而不是字符串,我有两个问题:

  • 如何使用Include设置接受lambda的模拟
  • 上述设置是否会级联到多个级别
  • include()
    是一种静态方法(扩展方法)。
    Moq
    不支持静态方法mock()

    要测试代码,需要将
    mockCarDbSet
    设置为返回
    IQueryable

    var carQuery=新列表
    {
    //添加汽车
    }
    IQueryable query=carQuery.AsQueryable();
    
    作为
    DataContext.Cars的结果返回
    query


    这些步骤将解决静态方法问题

    多亏@Old-Fox提醒我Moq不能与静态成员一起使用,我找到了一种使用Microsoft Fakes的方法。填隙片允许您使用静态方法填隙。我使用Moq为每个实体设置
    Mock
    对象:

    var carData = new List<Car>{new Car{ Trim = "Whatever" }};  
    var mockCarSet = new Mock<DbSet<Car>>();
    mockCarSet.As<IQueryable<Car>>().Setup(m => m.Provider).Returns(carData.Provider);
    mockCarSet.As<IQueryable<Car>>().Setup(m => m.Expression).Returns(carData.Expression);
    mockCarSet.As<IQueryable<Car>>().Setup(m => m.ElementType).Returns(carData.ElementType);
    mockCarSet.As<IQueryable<Car>>().Setup(m => m.GetEnumerator()).Returns(carData.GetEnumerator);
    var mockMakeSet = new Mock<DbSet<Make>>();
    //do the same stuff as with Car for IQueryable Setup
    var mockModelSet = new Mock<DbSet<Model>>();
    //do the same stuff as with Car for IQueryable Setup
    using(ShimsContext.Create())
    {
        //hack to return the first, since this is all mock data anyway
        ShimModel.AllInstances.MakeGet = model => mockMakeSet.Object.First();
        ShimCar.AllInstances.ModelGet = car => mockModelSet.Object.First();
        //run the test
    }
    
    var carData=newlist{newcar{Trim=“Whatever”};
    var mockCarSet=new Mock();
    mockCarSet.As().Setup(m=>m.Provider).返回(carData.Provider);
    mockCarSet.As().Setup(m=>m.Expression).Returns(carData.Expression);
    mockCarSet.As().Setup(m=>m.ElementType).Returns(carData.ElementType);
    mockCarSet.As().Setup(m=>m.GetEnumerator()).Returns(carData.GetEnumerator);
    var mockMakeSet=new Mock();
    //对IQueryable设置执行与汽车相同的操作
    var mockModelSet=new Mock();
    //对IQueryable设置执行与汽车相同的操作
    使用(ShimsContext.Create())
    {
    //hack返回第一个,因为这都是模拟数据
    ShimModel.AllInstances.MakeGet=model=>mockMakeSet.Object.First();
    ShimCar.AllInstances.ModelGet=car=>mockModelSet.Object.First();
    //运行测试
    }
    
    实际上,Moq处理.Include(It.IsAny)很好,这对DbSet.Include(“SomeEntity”)非常有效。请参见此答案:链接中的示例使用object方法。此方法获取字符串作为参数()。在代码中,您使用扩展方法。这里的一个小问题是,第一个使用if Include(…)的方法是DbSet(可以模拟)的方法,然后返回IQueryable。因此,第二个调用是使用IQueryable的静态Include(…)扩展方法执行的。@Phil,ammm。。。我想你应该再检查一遍操作码。。。正如我写给OP的一样,一个解决方法是设置
    DataContext.Cars
    以返回一个汽车列表。。。。顺便说一句,3个月后我在老狐狸网站上发布了(与这个问题相关…)。谢谢你的建议。只是我发现这个答案只有在使用DbSet的Include方法时才有效,而对于QueryableExtensions.Include方法则不行。