You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 19:20:17