Skip to content
Bitzsoft.Integrationsbitzsoft.integrations

Guide

单元测试

使用 Mock HttpMessageHandler 测试 Provider 实现,Result 断言模式。

Last updated

Provider 的核心逻辑是构造请求、解析响应和转换错误。单元测试通过 Mock HttpMessageHandler 隔离网络,验证这三条路径。

测试结构

tests/Bitzsoft.Integrations.Sms.Tests/AliyunSmsServiceTests.cs
public class AliyunSmsServiceTests
{
private readonly HttpTestHelper _http = new();
[Fact]
public async Task SendAsync_Success_Returns_Ok_Result()
{
// ① Arrange——配置 Mock 响应
_http.RespondWith("""
{"Code":"OK","RequestId":"req-123","BizId":"biz-456"}
""");
var options = new AliyunSmsOptions
{
AccessKeyId = "test-key",
AccessKeySecret = "test-secret",
SignName = "Bitzsoft",
};
var services = new ServiceCollection();
services.AddAliyunSms(o =>
{
o.AccessKeyId = options.AccessKeyId;
o.AccessKeySecret = options.AccessKeySecret;
o.SignName = options.SignName;
});
// ② 替换 HttpClient 为 Mock
services.AddHttpClient<AliyunSmsService>()
.ConfigurePrimaryHttpMessageHandler(() => _http.Handler);
var sp = services.BuildServiceProvider();
var sms = sp.GetRequiredService<ISMS>();
// ③ Act
var result = await sms.SendAsync(new SmsMessage
{
To = "13800138000",
TemplateId = "SMS_123",
TemplateParams = new() { ["code"] = "123456" },
});
// ④ Assert——Result 模式的断言
result.Success.Should().BeTrue();
result.RequestId.Should().Be("req-123");
result.BizId.Should().Be("biz-456");
}
[Fact]
public async Task SendAsync_Provider_Error_Returns_Fail_Result()
{
// ① 模拟厂商返回业务错误
_http.RespondWith("""
{"Code":"isv.BUSINESS_LIMIT_CONTROL","Message":"业务限流"}
""");
// ... 注册和获取 service ...
var result = await sms.SendAsync(message);
// ② 断言失败结果的结构化错误码
result.Success.Should().BeFalse();
result.ErrorCode.Should().Be("isv.BUSINESS_LIMIT_CONTROL");
result.ErrorMessage.Should().Contain("业务限流");
}
[Fact]
public async Task SendAsync_Network_Error_Returns_Exception_Result()
{
// ① 模拟网络异常
_http.Throw(new HttpRequestException("Connection refused"));
var result = await sms.SendAsync(message);
// ② 网络错误被捕获并转换为失败 Result
result.Success.Should().BeFalse();
result.ErrorCode.Should().Be("EXCEPTION");
}
}

Result 断言模式

断验内容成功路径失败路径
IsSuccess / SuccessShould().BeTrue()Should().BeFalse()
DataShould().NotBeNull() + 字段断言Should().BeNull()
ErrorCodeShould().BeNull()Should().Be("EXPECTED_CODE")
ErrorMessageShould().BeNull()Should().Contain("expected message")

HttpTestHelper

tests/Bitzsoft.Integrations.Sms.Tests/TestInfrastructure/HttpTestHelper.cs
public class HttpTestHelper : IDisposable
{
public HttpMessageHandlerMock Handler { get; } = new();
public void RespondWith(string json, int statusCode = 200) { ... }
public void Throw(Exception ex) { ... }
public void Dispose() => Handler.Dispose();
}

HttpMessageHandlerMock 继承 HttpMessageHandler,通过 ConfigurePrimaryHttpMessageHandler 注入到 HttpClient 管道。

相关

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%