C# 使用Moq,是否可以按类型设置模拟表?
在下面的代码中,我试图根据传递给MockDbSet方法的数据类型设置mock表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
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);