使用Moq进行单元测试:如何更新单个属性
问题描述
我正在使用nUnit和Moq编写单元测试,需要大量模拟数据。为此创建了辅助方法MockLotsOfData以避免在每个测试用例中重复模拟数据,简化后的代码如下:
protected void MockLotsOfData() { var orders = new List<Order>() { new Order() { Id = 1234, Total = 67.95, ExpressShip = false }, new Order() { Id = 5678, Total = 178.34, ExpressShip = false } }; var mockDbSetOrders = orders.AsMockDbSet(); this._mockDbContext.Setup(x => x.ORDERS).Returns(mockDbSetOrders.Object); }
现在我希望修改集合中单个对象的属性以测试不同场景,以下是简化后的测试用例代码:
[Test, Category("Unit")] public void OrderService_ProcessOrderWithExpressShipping_ReturnsSuccess() { //Arrange var service = this.CreateService(); var request = new OrderRequest() { OrderNumber = 1234 }; this.MockLotsOfData(); // 求助:如何修改Id为1234的Order的ExpressShip属性值? this._mockDbContext.SetupProperty(x => x.ORDERS.Where(y => y.Id = 1234)).Select(z => z.ExpressShip).Returns(true); //Act var response = service.ProcessOrder(request); //Assert Assert.IsTrue(response.Successful); }
我想要更新模拟数据中的单个属性值来测试不同场景,请问这是否可行?
解决方案
当然可行,以下是两种实用的实现方式:
方法1:调整辅助方法返回原始集合,直接修改对象
先修改MockLotsOfData方法,让它返回创建的订单列表,这样就能在测试用例中直接定位并修改目标对象:
protected List<Order> MockLotsOfData() { var orders = new List<Order>() { new Order() { Id = 1234, Total = 67.95, ExpressShip = false }, new Order() { Id = 5678, Total = 178.34, ExpressShip = false } }; var mockDbSetOrders = orders.AsMockDbSet(); this._mockDbContext.Setup(x => x.ORDERS).Returns(mockDbSetOrders.Object); return orders; }
在测试用例中获取列表并修改属性:
[Test, Category("Unit")] public void OrderService_ProcessOrderWithExpressShipping_ReturnsSuccess() { //Arrange var service = this.CreateService(); var request = new OrderRequest() { OrderNumber = 1234 }; var orders = this.MockLotsOfData(); // 修改Id为1234的订单属性 var targetOrder = orders.FirstOrDefault(o => o.Id == 1234); if(targetOrder != null) { targetOrder.ExpressShip = true; } //Act var response = service.ProcessOrder(request); //Assert Assert.IsTrue(response.Successful); }
方法2:从已Mock的DbSet中获取对象修改
如果不想改动MockLotsOfData方法,可以直接从Mock好的ORDERS集合中取出目标对象修改:
[Test, Category("Unit")] public void OrderService_ProcessOrderWithExpressShipping_ReturnsSuccess() { //Arrange var service = this.CreateService(); var request = new OrderRequest() { OrderNumber = 1234 }; this.MockLotsOfData(); // 从Mock的DbSet中获取订单并修改 var targetOrder = this._mockDbContext.ORDERS.FirstOrDefault(o => o.Id == 1234); if(targetOrder != null) { targetOrder.ExpressShip = true; } //Act var response = service.ProcessOrder(request); //Assert Assert.IsTrue(response.Successful); }
注意事项
- 你原来写的
SetupProperty用法错误,Moq的SetupProperty用于配置可读写的单个属性,不能直接针对Linq查询结果设置返回值。 - 确保
Order类的ExpressShip属性是可修改的(非只读)。
内容的提问来源于stack exchange,提问作者PixelPaul
相关产品推荐
相关产品推荐

