Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/webpack/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# 如何将此EF模拟设置代码编写为可重用的通用样板文件?_C#_Entity Framework_Unit Testing_Generics_Moq - Fatal编程技术网

C# 如何将此EF模拟设置代码编写为可重用的通用样板文件?

C# 如何将此EF模拟设置代码编写为可重用的通用样板文件?,c#,entity-framework,unit-testing,generics,moq,C#,Entity Framework,Unit Testing,Generics,Moq,我正在使用moq、ef 6和xunit。我发现自己一遍又一遍地写这段代码,并认为也许我可以把它变成一个通用方法,但遇到了一些麻烦 public static void CreateSalesMock(List<Sale> sales, Mock<DatabaseContext> dbContextMock) { var data = sales.AsQueryable(); var mockSet = new Mock<DbSet<Sale&

我正在使用moq、ef 6和xunit。我发现自己一遍又一遍地写这段代码,并认为也许我可以把它变成一个通用方法,但遇到了一些麻烦

public static void CreateSalesMock(List<Sale> sales, Mock<DatabaseContext> dbContextMock)
{
    var data = sales.AsQueryable();

    var mockSet = new Mock<DbSet<Sale>>();
    mockSet.As<IQueryable<Sale>>()
           .Setup(x => x.Provider)
           .Returns(data.Provider);
    mockSet.As<IQueryable<Sale>>()
           .Setup(x => x.Expression)
           .Returns(data.Expression);
    mockSet.As<IQueryable<Sale>>()
           .Setup(x => x.ElementType)
           .Returns(data.ElementType);
    mockSet.As<IQueryable<Sale>>()
           .Setup(x => x.GetEnumerator())
           .Returns(data.GetEnumerator());

    dbContextMock.Setup(x => x.Sales).Returns(mockSet.Object);
}
publicstaticvoid CreateSalesMock(List sales,Mock dbContextMock)
{
var data=sales.AsQueryable();
var mockSet=new Mock();
mockSet.As()
.Setup(x=>x.Provider)
.Returns(data.Provider);
mockSet.As()
.Setup(x=>x.Expression)
.Returns(data.Expression);
mockSet.As()
.Setup(x=>x.ElementType)
.Returns(data.ElementType);
mockSet.As()
.Setup(x=>x.GetEnumerator())
.Returns(data.GetEnumerator());
dbContextMock.Setup(x=>x.Sales).Returns(mockSet.Object);
}
现在我的数据库中有很多其他的表,所以如果我能写一个方法,它可以接收数据列表并进行设置,这样我就可以通过它模拟查询了,这将是非常棒的

public static void CreateMockSet<T, TA, TB>(T dataList, TA model, 
    Func<TB> lambda, Mock<DatabaseContext> dbContextMock) 
     where T : List<T>
     where TA: Mock<DbSet<TA>>
{
    var data = dataList.AsQueryable();

    model.As<IQueryable<T>>()
         .Setup(x => x.Provider)
         .Returns(data.Provider);
    model.As<IQueryable<T>>()
         .Setup(x => x.Expression)
         .Returns(data.Expression);
    model.As<IQueryable<T>>()
         .Setup(x => x.ElementType)
         .Returns(data.ElementType);
    model.As<IQueryable<T>>()
         .Setup(x => x.GetEnumerator())
         .Returns(data.GetEnumerator());

    dbContextMock.Setup(x => lambda);
}
publicstaticvoidcreatemockset(T数据列表、TA模型、,
Func lambda,Mock dbContextMock)
其中T:List
TA:Mock在哪里
{
var data=dataList.AsQueryable();
model.As()
.Setup(x=>x.Provider)
.Returns(data.Provider);
model.As()
.Setup(x=>x.Expression)
.Returns(data.Expression);
model.As()
.Setup(x=>x.ElementType)
.Returns(data.ElementType);
model.As()
.Setup(x=>x.GetEnumerator())
.Returns(data.GetEnumerator());
dbContextMock.Setup(x=>lambda);
}

到目前为止,我已经做到了,但我不确定这是否有效。我无法通过“lambda”部分(例如
x=>x.Sales
),所以我甚至无法测试它

Tim Larson已经为这个样板代码提供了一个很好的解决方案:

公共静态类DbSetMocking
{
私有静态模拟CreateMockSet(IQueryable数据)
T:在哪里上课
{
var queryableData=data.AsQueryable();
var mockSet=new Mock();
mockSet.As().Setup(m=>m.Provider)
.Returns(queryableData.Provider);
mockSet.As().Setup(m=>m.Expression)
.Returns(queryableData.Expression);
mockSet.As().Setup(m=>m.ElementType)
.Returns(queryableData.ElementType);
mockSet.As().Setup(m=>m.GetEnumerator())
.Returns(queryableData.GetEnumerator());
返回模拟集;
}
公共静态IReturnsResult返回数据集(
这是一个设置,
第[]实体)
地点:班级
其中TContext:DbContext
{
模拟模拟集;
ReturnsDbSet(设置、实体、外部模拟集);
}
公共静态IReturnsResult返回数据集(
这是一个设置,
可查询实体)
地点:班级
其中TContext:DbContext
{
模拟模拟集;
ReturnsDbSet(设置、实体、外部模拟集);
}
公共静态IReturnsResult返回数据集(
这是一个设置,
IEnumerable实体)
地点:班级
其中TContext:DbContext
{
模拟模拟集;
ReturnsDbSet(设置、实体、外部模拟集);
}
公共静态IReturnsResult返回数据集(
这是一个设置,
TEntity[]实体,外部模拟模拟集)
地点:班级
其中TContext:DbContext
{
mockSet=CreateMockSet(entities.AsQueryable());
返回setup.Returns(mockSet.Object);
}
公共静态IReturnsResult返回数据集(
这是一个设置,
IQueryable实体,out Mock mockSet)
地点:班级
其中TContext:DbContext
{
mockSet=CreateMockSet(实体);
返回setup.Returns(mockSet.Object);
}
公共静态IReturnsResult返回数据集(
这是一个设置,
IEnumerable实体,out Mock mockSet)
地点:班级
其中TContext:DbContext
{
mockSet=CreateMockSet(entities.AsQueryable());
返回setup.Returns(mockSet.Object);
}
}
然后在UT中,按如下方式使用它:

var context = new Mock<DatabaseContext>();
context.setup(x => x.Sales).ReturnsDbSet(new List<Sale>(){put here the items..});
var context=newmock();
context.setup(x=>x.Sales).ReturnsDbSet(新列表(){将项目放在这里..});
编辑

我更新了代码。现在还有3个重载允许对
DbSet
属性进行验证:

    [TestMethod]
    public void TestMethod1()
    {
        var sales = new List<Sale>
        {
            new Sale() {id = 1},
            new Sale() {id = 6},
            new Sale() {id = 5},
            new Sale() {id = 4},
            new Sale() {id = 3},
            new Sale() {id = 2}
        };
        var fakeContest = new Mock<SalesContext>();
        Mock<DbSet<Sale>> fakeSet;
        fakeContest.Setup(context => context.Sales).ReturnsDbSet(sales, out fakeSet);

        var itemsToRemove = sales.Where(sale => sale.id%2 == 0);


        fakeContest.Object.Sales.RemoveRange(itemsToRemove);


        fakeSet.Verify(set => set.RemoveRange(itemsToRemove));

    }
[TestMethod]
公共void TestMethod1()
{
var销售=新列表
{
new Sale(){id=1},
new Sale(){id=6},
new Sale(){id=5},
new Sale(){id=4},
new Sale(){id=3},
new Sale(){id=2}
};
var fakeContest=new Mock();
假假面具;
Setup(context=>context.Sales).ReturnsDbSet(Sales,out fakeSet);
var itemsToRemove=sales.Where(sale=>sale.id%2==0);
fakeContest.Object.Sales.RemoveRange(itemsToRemove);
验证(set=>set.RemoveRange(itemsToRemove));
}

我认为您希望更改
where
约束以引入一个接口:
where T:List
。我建议您查看一下构建器模式,请参见@ToddSprang,我不确定IBase将是什么。你能再举个例子吗?酷,这就是我想要的,但是如果我需要在模拟集中添加更多的设置,会发生什么呢?例如,我想看看在我对SalesMock运行验证之前是否调用了RemoveAnge,这是否有效。但现在我没有了,我不知道该怎么办。我试图通过dbContext.verify(x=>x.Sales.RemoveRange(…)进行验证,但总是失败。@chobo2不要这样做<代码>上下文。Sales是
Sales
列表,它是一个BCL集合。你不应该嘲笑别人。不要这样做,而是验证列表不再是c
    [TestMethod]
    public void TestMethod1()
    {
        var sales = new List<Sale>
        {
            new Sale() {id = 1},
            new Sale() {id = 6},
            new Sale() {id = 5},
            new Sale() {id = 4},
            new Sale() {id = 3},
            new Sale() {id = 2}
        };
        var fakeContest = new Mock<SalesContext>();
        Mock<DbSet<Sale>> fakeSet;
        fakeContest.Setup(context => context.Sales).ReturnsDbSet(sales, out fakeSet);

        var itemsToRemove = sales.Where(sale => sale.id%2 == 0);


        fakeContest.Object.Sales.RemoveRange(itemsToRemove);


        fakeSet.Verify(set => set.RemoveRange(itemsToRemove));

    }