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

.NET 6中如何对Dapr订阅者进行单元测试?

如何Mock测试带有Topic特性的API控制器操作

前置依赖

首先确保测试项目安装了以下NuGet包:

  • xunit(测试框架)
  • Moq(Mock工具)
  • Microsoft.AspNetCore.Mvc(控制器相关依赖,单元测试用)
  • Microsoft.AspNetCore.Mvc.Testing(集成测试用,可选)

方案1:单元测试(直接Mock服务+实例化控制器)

这种方式专注于测试控制器逻辑,无需启动完整Web服务。假设你的控制器依赖ICustomService接口:

测试代码示例

using Moq;
using Xunit;
using YourApp.Controllers;
using YourApp.Services;
using YourApp.Dtos;

public class TestControllerTests
{
    private readonly Mock<ICustomService> _mockService;
    private readonly TestController _controller;

    public TestControllerTests()
    {
        // 初始化Mock服务
        _mockService = new Mock<ICustomService>();
        // 注入Mock服务到控制器
        _controller = new TestController(_mockService.Object);
    }

    [Fact]
    public async Task Post_ReceivesValidDto_CallsServiceExecute()
    {
        // 准备测试数据
        var testDto = new CustomDto
        {
            // 填充Dto的测试属性,例如:
            // Id = 1,
            // Content = "Test message"
        };

        // 设置Mock服务的预期行为:调用Execute时返回完成任务
        _mockService.Setup(s => s.Execute(testDto, CancellationToken.None))
                    .Returns(Task.CompletedTask);

        // 执行控制器方法
        await _controller.Post(testDto);

        // 验证:服务的Execute方法是否被正确调用一次
        _mockService.Verify(s => s.Execute(testDto, CancellationToken.None), Times.Once);
    }
}

方案2:集成测试(模拟完整HTTP请求+替换服务)

如果需要验证路由、请求序列化等完整流程,可以用WebApplicationFactory启动测试服务器,并替换真实服务为Mock实例:

测试代码示例

using Xunit;
using Microsoft.AspNetCore.Mvc.Testing;
using Moq;
using YourApp.Services;
using YourApp.Dtos;
using System.Net.Http.Json;

public class TestControllerIntegrationTests : IClassFixture<WebApplicationFactory<Program>>
{
    private readonly HttpClient _testClient;
    private readonly Mock<ICustomService> _mockService;

    public TestControllerIntegrationTests(WebApplicationFactory<Program> factory)
    {
        _mockService = new Mock<ICustomService>();

        // 替换应用中的真实服务为Mock实例
        _testClient = factory.WithWebHostBuilder(builder =>
        {
            builder.ConfigureServices(services =>
            {
                // 移除原有服务注册
                var serviceDescriptor = services.SingleOrDefault(d => d.ServiceType == typeof(ICustomService));
                if (serviceDescriptor != null)
                {
                    services.Remove(serviceDescriptor);
                }
                // 添加Mock服务
                services.AddScoped(_ => _mockService.Object);
            });
        }).CreateClient();
    }

    [Fact]
    public async Task Post_ValidRequest_ReturnsSuccessAndCallsService()
    {
        // 准备测试数据
        var testDto = new CustomDto
        {
            // 填充测试属性
        };

        // 设置Mock服务的预期行为
        _mockService.Setup(s => s.Execute(testDto, It.IsAny<CancellationToken>()))
                    .Returns(Task.CompletedTask);

        // 发送HTTP POST请求
        var response = await _testClient.PostAsJsonAsync("/test", testDto);

        // 验证请求成功(返回2xx状态码)
        response.EnsureSuccessStatusCode();
        // 验证服务方法被调用一次
        _mockService.Verify(s => s.Execute(testDto, It.IsAny<CancellationToken>()), Times.Once);
    }
}

关键注意事项

  • 确保ICustomService是抽象接口,如果是具体类,需要将Execute方法声明为virtual,否则Moq无法Mock。
  • 若CustomDto带有数据验证特性(如[Required]),测试时要传入符合验证规则的实例;或者在单元测试中手动设置控制器的验证状态。
  • [Topic("pubsub", "test")]是消息订阅的标记特性,对HTTP请求的测试逻辑无影响,测试时依然通过[HttpPost("test")]定义的路由访问。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 05:03:18