如何用xUnit.net和Moq测试整洁架构+CQRS下的控制器?
用xUnit和Moq测试CQRS架构下的Product API控制器
对于CQRS架构的API控制器,核心是测试控制器的逻辑——也就是它是否正确调用IMediator,并将结果正确包装为HTTP响应。不需要重构应用层的命令/查询,只需要Mock控制器依赖的IMediator接口即可。
步骤1:准备测试依赖
确保你的xUnit测试项目已安装以下NuGet包:
xunitxunit.runner.visualstudio(可选,方便在VS中运行)MoqMediatR(与API项目版本一致)Microsoft.AspNetCore.Mvc(用于识别OkObjectResult等控制器返回类型)
步骤2:编写测试类
以下是针对你的GetAllProducts方法的完整测试示例:
using Xunit; using Moq; using MediatR; using YourApi.Controllers; // 替换为你的控制器命名空间 using YourApi.Queries; // 替换为GetAllProductsQuery所在的命名空间 using YourApi.Models; // 替换为Product模型所在的命名空间 public class ProductsControllerTests { private readonly Mock<IMediator> _mockMediator; private readonly ProductsController _controller; public ProductsControllerTests() { // 初始化Mock的IMediator实例 _mockMediator = new Mock<IMediator>(); // 注入Mock对象,构造控制器实例 _controller = new ProductsController(_mockMediator.Object); } [Fact] public async Task GetAllProducts_ReturnsOkResult_WithExpectedProducts() { // Arrange:准备测试数据和Mock行为 var testProducts = new List<Product> { new Product { Id = 1, Name = "Test Product 1" }, new Product { Id = 2, Name = "Test Product 2" } }; // 配置Mock:当调用Mediator.Send(GetAllProductsQuery)时,返回预设的产品列表 _mockMediator.Setup(m => m.Send(It.IsAny<GetAllProductsQuery>(), default)) .ReturnsAsync(testProducts); // Act:执行要测试的控制器方法 var result = await _controller.GetAllProducts(); // Assert:验证结果是否符合预期 // 确认返回的是OkObjectResult var okResult = Assert.IsType<OkObjectResult>(result); // 确认返回的数据是正确的产品列表 var returnedProducts = Assert.IsType<List<Product>>(okResult.Value); Assert.Equal(2, returnedProducts.Count); Assert.Equal("Test Product 1", returnedProducts[0].Name); } }
关键说明
- Mock的核心是隔离依赖:控制器只依赖
IMediator,我们不需要关心GetAllProductsQuery的具体处理逻辑(那是QueryHandler的单元测试范围),只需要验证控制器是否正确触发查询并返回响应。 - 测试边界清晰:这个测试只覆盖控制器的职责——接收HTTP请求、调用Mediator、返回正确的HTTP结果。
- 异常场景扩展:如果需要测试Mediator抛出异常的情况,可以修改Mock配置:
然后断言控制器返回的是_mockMediator.Setup(m => m.Send(It.IsAny<GetAllProductsQuery>(), default)) .ThrowsAsync(new Exception("Query failed"));StatusCodeResult或对应错误类型。
注意事项
- 确保测试项目能访问到
GetAllProductsQuery、Product等类:可以直接引用API项目,或者将这些类放在独立的类库中供API和测试项目共同引用。 - 不要重复实现应用层逻辑:你的错误尝试是重构应用层,这完全没必要——单元测试控制器的核心是隔离外部依赖,而非重新实现业务逻辑。
内容的提问来源于stack exchange,提问作者Aboliii
相关产品推荐
相关产品推荐

