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

使用Fluent Validation和Xunit编写单元测试时,如何正确抛出ValidationException?

问题分析与修复方案

你的测试报错显示期望捕获AggregateException但实际无异常抛出,核心问题出在异步方法的异常处理方式和Mock匹配逻辑上,以下是具体修复步骤:

1. 改用异步断言方法

ProcessOrderAsync是异步方法,用.Wait()同步等待会导致异常被异常包装或吞掉,Xunit提供了专门的异步断言方法Assert.ThrowsAsync,应直接替代同步的Assert.Throws。

2. 修正Mock的匹配逻辑

你当前的Mock设置是_mock.Setup(x => x.Validate(order)).Throws(...),这是引用匹配——只有当ProcessOrderAsync内部传入的Order实例和你setup中用的order完全是同一个对象时,才会触发抛出异常。如果ProcessOrderAsync内部对Order做了复制、转换,这个Mock就不会生效。建议改用类型匹配,确保任意Order实例调用Validate都触发异常(或根据验证规则调整匹配条件)。

修复后的完整测试代码

[Fact]
[Trait("Category", "Unit")]
public async Task Should_MyOrder_Throw_ValidationException_Successfully()
{
    // Arrange
    var orderId = "123";

    var fixture = new Fixture();
    fixture.Customize<Order>(composer =>
        composer.With(_ => _.OrderNo, orderId)
                .With(_ => _.DeliveryNo, 0)
                .With(_ => _.Name, "XXXXXX"));

    var order = fixture.Create<Order>();
    var orderEvent = new OrderEvent(
        CloudEventFactory.CreateNew(OrderEvents.OrderUpsert, orderId, order));

    // 改用It.IsAny<Order>()确保匹配任意Order实例,避免引用匹配失效
    _mock.Setup(x => x.Validate(It.IsAny<Order>()))
         .Throws(new ValidationException("ValidationException"));

    _orderRepositoryMock
        .Setup(_ => _.FindByOrderIdAsync(orderId, OrderEvents.EventType, It.IsAny<CancellationToken>()))
        .ReturnsAsync((OrderEvent)null);

    // Act & Assert
    // 直接用ThrowsAsync捕获异步方法抛出的ValidationException
    var exception = await Assert.ThrowsAsync<ValidationException>(() => 
        _sut.ProcessOrderAsync(orderEvent, new CancellationToken()));
    
    // 可选:验证异常消息是否符合预期
    Assert.Equal("ValidationException", exception.Message);
}

额外说明

  • 如果ProcessOrderAsync内部确实会把ValidationException包装成AggregateException抛出(比如用了Task.Wait()或其他同步阻塞逻辑),可改用如下断言方式:
    var aggregateException = await Assert.ThrowsAsync<AggregateException>(() => 
        _sut.ProcessOrderAsync(orderEvent, new CancellationToken()));
    Assert.IsType<ValidationException>(aggregateException.InnerException);
    
  • 可在测试末尾加_mock.Verify(x => x.Validate(It.IsAny<Order>()), Times.Once);,验证Validate方法确实被调用,这是排查Mock未触发的常用手段。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 16:25:21