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

C#单元测试中Mock ASP.NET控制器抛出ServiceNotFound错误的实现方案

核心思路

你要触发ServiceNotFound类型的ServiceException,本质是让IOrdersService.PutOrdersAsync执行到抛出该异常的业务分支,根据测试目标不同,有两种实现方案:


方案1:测试控制器的异常捕获逻辑

如果你的测试目标是验证控制器能正确捕获并处理ServiceException,不需要构造真实的OrdersService实例,直接MockIOrdersService的行为即可:

// Tests.cs 示例代码(基于Moq框架)
using Moq;
using Microsoft.AspNetCore.Mvc;
using System.Net;

// 1. 构造IOrdersService模拟对象
var mockOrdersService = new Mock<IOrdersService>();
// 2. 配置PutOrdersAsync被调用时直接抛出目标NotFound异常
mockOrdersService
    .Setup(s => s.PutOrdersAsync())
    .ThrowsAsync(new ServiceException(HttpStatusCode.NotFound, "目标服务未找到"));

// 3. 将模拟服务注入控制器
var controller = new OrdersController(mockOrdersService.Object);

// 4. 调用接口并断言结果符合预期
var result = await controller.PutOrdersAsync();
var objectResult = result as ObjectResult;
Assert.Equal((int)HttpStatusCode.NotFound, objectResult.StatusCode);

方案2:测试服务层本身的异常抛出逻辑

如果你的测试目标是验证OrdersService本身能在资源不存在时正确抛出ServiceNotFound异常,需要配置DbContextMock返回触发异常的条件:
假设你的OrdersService.PutOrdersAsync内部逻辑是「先查询对应资源,查询不到则抛出NotFound异常」,按如下方式配置Mock即可:

// Tests.cs 示例代码(基于Moq框架)
using Moq;
using System.Net;
using Microsoft.EntityFrameworkCore;

// 1. 构造空的模拟DbSet,模拟查询不到资源的场景
var emptyOrderSet = new List<Order>().AsQueryable().BuildMockDbSet();
// 2. 配置DbContext返回空的DbSet
var context = new DbContextMock();
context.Setup(c => c.Orders).Returns(emptyOrderSet.Object);

// 3. 构造真实的OrdersService实例
var service = GetOrdersService(context.Object, _pdcClientFactory.Object);

// 4. 调用方法断言抛出预期异常
var exception = await Assert.ThrowsAsync<ServiceException>(() => service.PutOrdersAsync());
Assert.Equal(HttpStatusCode.NotFound, exception.StatusCode);

注意事项

  • 如果使用非Moq的Mock框架(如NSubstitute),只需替换对应配置模拟行为的语法即可,核心逻辑一致。
  • 请先确认你的ServiceException构造支持传入HttpStatusCode.NotFound作为状态码参数,保证异常的StatusCode属性符合预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 13:24:05