Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.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# 使用Moq,是否可以按类型设置模拟表?_C#_Entity Framework_Moq - Fatal编程技术网

C# 使用Moq,是否可以按类型设置模拟表?

C# 使用Moq,是否可以按类型设置模拟表?,c#,entity-framework,moq,C#,Entity Framework,Moq,在下面的代码中,我试图根据传递给MockDbSet方法的数据类型设置mock表 private Mock<DbContext> mockContext = new Mock<DbContext>(); public DbContext GetContext() { return mockContext.Object; } public void MockDbSet<T>(params T[] sourceList) where T : class

在下面的代码中,我试图根据传递给MockDbSet方法的数据类型设置mock表

private Mock<DbContext> mockContext = new Mock<DbContext>();

public DbContext GetContext()
{
    return mockContext.Object;
}

public void MockDbSet<T>(params T[] sourceList) where T : class
{
    var queryable = sourceList.AsQueryable();

    var dbSet = new Mock<DbSet<T>>();
    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());

    mockContext.Setup(c => c.Set(typeof(T))).Returns(dbSet.Object);
}
我试过了

mockContext.Setup(c => c.Set<T>()).Returns(dbSet.Object);
mockContext.Setup(c=>c.Set()).Returns(dbSet.Object);
这不会引发异常,但也不会设置任何数据

可以这样设置表格吗


感谢您在存储库级别概述模拟:

通过合同接口与Repostory交互的给定服务/控制器代码:

public interface IOrderRepository
{
   IQueryable<Order> GetOrderById (int orderId);
   IQueryable<Order> GetOrdersForCustomer (int customerId);
}
现在当你去测试你的控制器

[Test]
public void EnsureSomeActionOnOrderDoesIt()
{
   var uowMock = new Mock<IUnitOfWork>();
   var uowFactoryMock = new Mock<IUnitOfWorkFactory>();
   var repositoryMock = new Mock<IOrderRepository>();
   var testOrderId = -1;
   var stubOrders = new [] { newOrder { /* populate expected data... */ } };

   uowMock.Setup(x=>x.Commit());
   uowFactoryMock.Setup(x=>x.Create()).Returns(uowMock.Object);
   repositoryMock.Setup(x=>x.GetOrderById(testOrderId)).Returns(stubOrders.AsQueryable());

   var testController = new OrderController(uowFactoryMock.Object, repositoryMock.Object);
   testController.SomeActionOnOrder(testOrderId);

   // Everything "touched" as expected? (did the code fetch the object? did it save the changes?)
   uowFactoryMock.VerifyAll();
   uowMock.VerifyAll();
   repositoryMock.VerifyAll();

   // Perform asserts on your stub order if SomeAction modified state as you expected.
}
[测试]
公共无效保证措施或命令()
{
var uowMock=new Mock();
var uowFactoryMock=new Mock();
var repositoryMock=new Mock();
var testOrderId=-1;
var stubOrders=new[]{newOrder{/*填充预期数据…*/};
安装程序(x=>x.Commit());
设置(x=>x.Create()).Returns(uowMock.Object);
Setup(x=>x.GetOrderById(testOrderId)).Returns(stubOrders.AsQueryable());
var testController=newordercontroller(uowFactoryMock.Object,repositoryMock.Object);
testController.SomeActionOrder(testOrderId);
//一切都按预期“触动了”(代码是否获取了对象?是否保存了更改?)
uowFactoryMock.VerifyAll();
uowMock.VerifyAll();
repositoryMock.VerifyAll();
//如果某个操作按预期修改了状态,则对存根订单执行断言。
}
针对实际数据库的集成测试将处理存储库预期涵盖的任何逻辑

我上面的存储库模式是IQueryable风格,或者,如果您返回一个实体,只需返回带有存根顺序的“存根”,然后返回它

我使用的模拟框架是Moq。仅基于内存,上述代码可能在语法上不完全正确。:)

就TDD/BDD而言,单元测试的目标是这些测试应该是可靠的可重复性,并且执行速度快,以便在开发过程中可以重复频繁地运行。保持存储库相对精简,并且不涉及业务逻辑决策,这意味着它们可以作为单元测试模拟的可靠分界点。存储库的工作是返回数据,因此通过在该点进行模拟,这意味着我们可以控制我们期望测试代码使用的数据。我们可以模拟它来返回对象、null、抛出异常,不管我们的测试场景希望我们的测试代码处理什么

在上面的示例中,我还演示了包装DB上下文的基本工作单元模式的使用。我用于EF的实现是Medhime的DB上下文范围工厂/定位器。例如,使用工作单元模式,我们还可以使用mock来验证测试中的代码是否正在保存数据。存储库需要有一个指向工作单元的链接(在构造函数中初始化,或按照Mehdime模式“定位”),但在测试服务和控制器时,我们并不关心这一方面,存储库只是模拟出来的,其目的是返回和(可选地)创建数据


我将让我的存储库充当实体的工厂(即带有产品详细信息和数量列表的CreateOrder()),以确保使用所有预期的引用链接和所需数据初始化新实体,而不是依赖于调用代码。为了检索新订单的参考数据,调用代码必须包含额外的查询等,因此我让它将视图模型数据传递到订单存储库,以解析、连接并返回有效的新订单实体。

要在存储库级别概述模拟,请执行以下操作:

通过合同接口与Repostory交互的给定服务/控制器代码:

public interface IOrderRepository
{
   IQueryable<Order> GetOrderById (int orderId);
   IQueryable<Order> GetOrdersForCustomer (int customerId);
}
现在当你去测试你的控制器

[Test]
public void EnsureSomeActionOnOrderDoesIt()
{
   var uowMock = new Mock<IUnitOfWork>();
   var uowFactoryMock = new Mock<IUnitOfWorkFactory>();
   var repositoryMock = new Mock<IOrderRepository>();
   var testOrderId = -1;
   var stubOrders = new [] { newOrder { /* populate expected data... */ } };

   uowMock.Setup(x=>x.Commit());
   uowFactoryMock.Setup(x=>x.Create()).Returns(uowMock.Object);
   repositoryMock.Setup(x=>x.GetOrderById(testOrderId)).Returns(stubOrders.AsQueryable());

   var testController = new OrderController(uowFactoryMock.Object, repositoryMock.Object);
   testController.SomeActionOnOrder(testOrderId);

   // Everything "touched" as expected? (did the code fetch the object? did it save the changes?)
   uowFactoryMock.VerifyAll();
   uowMock.VerifyAll();
   repositoryMock.VerifyAll();

   // Perform asserts on your stub order if SomeAction modified state as you expected.
}
[测试]
公共无效保证措施或命令()
{
var uowMock=new Mock();
var uowFactoryMock=new Mock();
var repositoryMock=new Mock();
var testOrderId=-1;
var stubOrders=new[]{newOrder{/*填充预期数据…*/};
安装程序(x=>x.Commit());
设置(x=>x.Create()).Returns(uowMock.Object);
Setup(x=>x.GetOrderById(testOrderId)).Returns(stubOrders.AsQueryable());
var testController=newordercontroller(uowFactoryMock.Object,repositoryMock.Object);
testController.SomeActionOrder(testOrderId);
//一切都按预期“触动了”(代码是否获取了对象?是否保存了更改?)
uowFactoryMock.VerifyAll();
uowMock.VerifyAll();
repositoryMock.VerifyAll();
//如果某个操作按预期修改了状态,则对存根订单执行断言。
}
针对实际数据库的集成测试将处理存储库预期涵盖的任何逻辑

我上面的存储库模式是IQueryable风格,或者,如果您返回一个实体,只需返回带有存根顺序的“存根”,然后返回它

我使用的模拟框架是Moq。仅基于内存,上述代码可能在语法上不完全正确。:)

就TDD/BDD而言,单元测试的目标是这些测试应该是可靠的可重复性,并且执行速度快,以便在开发过程中可以重复频繁地运行。保持存储库相对精简,并且不涉及业务逻辑决策,这意味着它们可以作为单元测试模拟的可靠分界点。存储库的工作是返回数据,因此通过在该点进行模拟,这意味着我们可以控制我们期望测试代码使用的数据。我们可以模拟它来返回对象、null、抛出异常,不管我们的测试场景希望我们的测试代码处理什么

在上面的示例中,我还演示了包装DB上下文的基本工作单元模式的使用。我用于EF的实现是Medhime的DB上下文范围工厂/
[Test]
public void EnsureSomeActionOnOrderDoesIt()
{
   var uowMock = new Mock<IUnitOfWork>();
   var uowFactoryMock = new Mock<IUnitOfWorkFactory>();
   var repositoryMock = new Mock<IOrderRepository>();
   var testOrderId = -1;
   var stubOrders = new [] { newOrder { /* populate expected data... */ } };

   uowMock.Setup(x=>x.Commit());
   uowFactoryMock.Setup(x=>x.Create()).Returns(uowMock.Object);
   repositoryMock.Setup(x=>x.GetOrderById(testOrderId)).Returns(stubOrders.AsQueryable());

   var testController = new OrderController(uowFactoryMock.Object, repositoryMock.Object);
   testController.SomeActionOnOrder(testOrderId);

   // Everything "touched" as expected? (did the code fetch the object? did it save the changes?)
   uowFactoryMock.VerifyAll();
   uowMock.VerifyAll();
   repositoryMock.VerifyAll();

   // Perform asserts on your stub order if SomeAction modified state as you expected.
}
public static Mock<DbSet<T>> MockList<T>(this List<T> list) where T: class 
        {
            var mockDbSet = new Mock<DbSet<T>>();

            var queryable = list.AsQueryable();

            mockDbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
            mockDbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
            mockDbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
            mockDbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(queryable.GetEnumerator());

            return mockDbSet;
        }
var myData = new List<MyDataType> { new MyDataType(), new MyDataType(), ....};
var mockDb = new Mock<MyContext>();
mockDb.Setup(x => x.MyDatas).Returns(myData.MockList().Object);