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

如何让NUnit测试在SaveOrderAllocation计算逻辑变更时自动失败?

解决单元测试无法检测SaveOrderAllocation逻辑变更的问题

问题背景

Presenter层的SaveOrderAllocation方法原本逻辑为:非无限分配模式下,计算预分配量的90%与预订单需求量(OpenQuantity+ReleasedQuantity+ShippedQuantity)的最大值,将该值赋值给内部创建的orderAllocationInput.PreorderAllocation字段后,调用ItemDao.SavePreorderAllocation。但当方法逻辑被修改为仅取90%预分配量时,现有NUnit单元测试未能自动失败,需在不修改原方法体的前提下调整测试断言,使其能检测到这类逻辑变更。

现有代码分析

原SaveOrderAllocation方法核心逻辑

public SaveActionResultWithCustomizedErrors<int> SaveOrderAllocation(OrderAllocation orderAllocation, FillOrderOutput fillOrderOutput)
{
    var saveResult = new SaveActionResultWithCustomizedErrors<int>();
    int? maxOfNinetyPercentAllocationQty = null;
    var title = new orderAllocationInput() {Ean = orderAllocation.Ean}; 

    try
    {
        if (!orderAllocation.IsUnlimitedAllocation)
        {
            if (orderAllocation.PreorderAllocationQty != null &
                orderAllocation.PreorderAllocationQty.HasValue)
            {
                var preDemandQty = (fillOrderOutput.OpenQuantity + fillOrderOutput.ReleasedQuantity + fillOrderOutput.ShippedQuantity);
                maxOfNinetyPercentAllocationQty = Math.Max(.9 * orderAllocation.PreorderAllocationQty.Value, preDemandQty).RoundToInt();
            }

            if (maxOfNinetyPercentAllocationQty != null) title.PreorderAllocation = maxOfNinetyPercentAllocationQty.Value;
        }
       
        ItemDao.SavePreorderAllocation(orderAllocation, fillOrderOutput);
        saveResult.SuccessfulItems.Add(orderAllocation.SystemId, orderAllocation.SystemId);
    }
    // 省略异常处理等代码
}

现有单元测试代码

[Test]
public void SaveOrderAllocation_With_OrderAllocationToMaxOf90Percent_Or_PreDemandQtyTest()
{
    // Arrange
    var orderAllocation = new OrderAllocation
    {
        Ean = "EAN123",
        Sysid = 1,
        PreorderAllocationQty = 100,
        IsUnlimitedAllocation = false
    };

    var fillOrderOutput = new FillOrderOutput
    {
        OpenQuantity = 80,
        ReleasedQuantity = 30,
        ShippedQuantity = 20
    };

    var preDemandQty = fillOrderOutput.OpenQuantity + fillOrderOutput.ReleasedQuantity + fillOrderOutput.ShippedQuantity;
    var expected = Math.Max(.9 * orderAllocation.PreorderAllocationQty.Value, preDemandQty).RoundToInt();

    // Act
    var result = Testee.SaveOrderAllocation(orderAllocation, fillOrderOutput);

    // Assert
    _itemDaoMock.Verify(x => x.SavePreorderAllocation(orderAllocation, fillOrderOutput), Times.Once());

    Assert.IsTrue(result.Success);
    Assert.That(result.FailedItems.Count, Is.EqualTo(0));
    Assert.That(result.SuccessfulItems.Count, Is.EqualTo(1));
    Assert.AreEqual(expected, preDemandQty);  // 这行断言完全无效
}

测试失效原因

现有测试存在两个关键问题:

  • 无效断言:Assert.AreEqual(expected, preDemandQty)中,expected是按原逻辑计算的130,而preDemandQty本身就是测试代码中硬算的130,与方法内部的计算逻辑完全无关,无论方法逻辑怎么改,这行断言永远成立。
  • 未验证核心逻辑:测试只验证了SavePreorderAllocation的调用次数,却没验证方法核心计算结果(即title.PreorderAllocation的值)是否被正确传递给了DAO层。

解决方案

调整测试逻辑,通过Mock验证SavePreorderAllocation被调用时,传入的参数中包含符合原逻辑的预期值。由于原方法中title是内部创建的,需通过参数匹配器验证其属性:

调整后的单元测试代码

[Test]
public void SaveOrderAllocation_With_OrderAllocationToMaxOf90Percent_Or_PreDemandQtyTest()
{
    // Arrange
    var orderAllocation = new OrderAllocation
    {
        Ean = "EAN123",
        Sysid = 1,
        PreorderAllocationQty = 100,
        IsUnlimitedAllocation = false
    };

    var fillOrderOutput = new FillOrderOutput
    {
        OpenQuantity = 80,
        ReleasedQuantity = 30,
        ShippedQuantity = 20
    };

    var preDemandQty = fillOrderOutput.OpenQuantity + fillOrderOutput.ReleasedQuantity + fillOrderOutput.ShippedQuantity;
    var expectedPreorderAllocation = Math.Max(.9 * orderAllocation.PreorderAllocationQty.Value, preDemandQty).RoundToInt();

    // Act
    var result = Testee.SaveOrderAllocation(orderAllocation, fillOrderOutput);

    // Assert
    // 验证DAO方法被调用时,传入的orderAllocationInput(即title)的PreorderAllocation等于预期值
    // 若SavePreorderAllocation实际接收OrderAllocation作为第一个参数,需调整匹配器验证对应属性
    _itemDaoMock.Verify(x => x.SavePreorderAllocation(
        It.Is<orderAllocationInput>(input => input.PreorderAllocation == expectedPreorderAllocation),
        fillOrderOutput), 
    Times.Once());

    // 保留基础结果断言
    Assert.IsTrue(result.Success);
    Assert.That(result.FailedItems.Count, Is.EqualTo(0));
    Assert.That(result.SuccessfulItems.Count, Is.EqualTo(1));
}

关键调整说明

  • 移除了无效的Assert.AreEqual(expected, preDemandQty)断言。
  • 修改_itemDaoMock.Verify,使用It.Is<T>参数匹配器,验证传入SavePreorderAllocation的orderAllocationInput对象的PreorderAllocation字段值是否符合原逻辑的预期值。
  • 如果原方法中SavePreorderAllocation的第一个参数是OrderAllocation,且方法内部将title.PreorderAllocation赋值给了orderAllocation的对应属性,则将匹配器改为验证OrderAllocation的该属性值。

这样修改后,当SaveOrderAllocation的计算逻辑被改为仅取90%预分配量时,expectedPreorderAllocation会是130,而实际传入DAO的PreorderAllocation会是90,Mock验证会失败,测试就能正确检测到逻辑变更。

内容的提问来源于stack exchange,提问作者Sandy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 12:32:04