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

VB.NET中如何Mock HttpResponseMessage的SendAsync方法?

解决VB.NET中Mock HttpClient的Protected Friend方法SendAsync的问题

问题核心

你遇到的两个错误根源在于:

  • SendAsync是HttpMessageHandler的Protected Friend方法,无法直接通过常规Setup访问
  • VB.NET中Moq处理Protected方法的语法和C#不同,不能直接用Lambda表达式,必须使用方法名字符串+参数类型的方式指定要Mock的方法

解决方案步骤

1. 导入必要的命名空间

确保测试类顶部导入Moq.Protected命名空间,这是Moq处理Protected方法的扩展所在:

Imports Moq
Imports Moq.Protected
Imports System.Net.Http
Imports System.Threading
Imports System.Threading.Tasks

2. 修正Mock Setup的语法

在VB.NET中,Mock Protected方法需要通过方法名的字符串来指定,并用ItExpr.IsAny替代It.IsAny(Protected方法Mock专用的匹配器)。同时因为SendAsync返回Task(Of HttpResponseMessage),需要用ReturnsAsync来返回异步结果。

另外,业务代码中调用了两个不同的API接口,需要根据请求的RequestUri返回对应的数据,避免两个请求返回相同内容导致测试不准确。

3. 修正测试方法的异步调用

因为GetUserPreferenceResponseData是异步方法,测试方法必须标记为Async Sub,并使用Await调用,否则拿到的result只是未完成的Task,无法正确断言。

修正后的完整测试代码

<TestMethod()> Public Async Sub GetUserPreferenceResponseData()
    'Arrange
    Dim methodName = System.Reflection.MethodBase.GetCurrentMethod().Name
    Dim testUserId As Long = 123 ' 指定测试用的ID
    Dim testTenant = "TestTenant" ' 模拟Account.CurrentTenant的值

    ' 模拟UserContents接口返回的数据
    Dim asuc As New ActivitySummary.UserContent() With {.UserContentId = 1, .UserContentName = "BB"}
    Dim ucList As New List(Of ActivitySummary.UserContent) From {asuc}
    Dim userContentJson = Newtonsoft.Json.JsonConvert.SerializeObject(ucList)

    ' 模拟Users接口返回的数据
    Dim testUserPrefs As New UserPreferences() With {.Id = testUserId}
    Dim userPrefsJson = Newtonsoft.Json.JsonConvert.SerializeObject(testUserPrefs)

    ' 模拟Account的CurrentTenant属性
    Dim accountMock = New Mock(Of IAccount)()
    accountMock.Setup(Function(x) x.CurrentTenant).Returns(testTenant)

    ' Mock HttpMessageHandler
    Dim handlerMock = New Mock(Of HttpMessageHandler)()
    handlerMock.Protected() _
        .Setup(Of Task(Of HttpResponseMessage))("SendAsync", _
            ItExpr.IsAny(Of HttpRequestMessage), _
            ItExpr.IsAny(Of CancellationToken)) _
        .ReturnsAsync(Function(request As HttpRequestMessage, token As CancellationToken)
                          ' 根据请求路径返回对应的数据
                          If request.RequestUri.ToString().EndsWith("/api/v1/UserContents") Then
                              Return New HttpResponseMessage With {
                                  .StatusCode = Net.HttpStatusCode.OK,
                                  .Content = New StringContent(userContentJson)
                              }
                          ElseIf request.RequestUri.ToString().EndsWith($"/api/v1/Users/{testTenant}/{testUserId}") Then
                              Return New HttpResponseMessage With {
                                  .StatusCode = Net.HttpStatusCode.OK,
                                  .Content = New StringContent(userPrefsJson)
                              }
                          Else
                              ' 其他请求返回404
                              Return New HttpResponseMessage(Net.HttpStatusCode.NotFound)
                          End If
                      End Function)

    ' 创建HttpClient
    Dim httpClient = New HttpClient(handlerMock.Object)

    ' 初始化待测试的业务类(假设其他依赖已正确Mock)
    Dim userPreferencesBL As New UserPreferencesBL(_Context, accountMock.Object, _dbConfigManager)

    'Action
    Dim result = Await userPreferencesBL.GetUserPreferenceResponseData(testUserId, httpClient)

    'Assert
    Assert.IsNotNull(result, $"{methodName} returned null, expected User Preferences.")
    Assert.AreEqual(testUserId, result.Id)
    Assert.IsNotNull(result.UserContentsList)
    Assert.AreEqual(1, result.UserContentsList.Count)
    Assert.AreEqual("BB", result.UserContentsList(0).UserContentName)
End Sub

关键语法说明

  • handlerMock.Protected():开启Protected方法的Mock模式
  • .Setup(Of Task(Of HttpResponseMessage))("SendAsync", ...):指定要Mock的方法名(字符串)和返回类型
  • ItExpr.IsAny(Of T):用于Protected方法的参数匹配,替代常规的It.IsAny
  • ReturnsAsync(Function(...)):异步返回结果,支持根据请求参数动态返回不同内容

这样修改后,就能解决你遇到的两个错误,同时正确Mock两个不同的API请求,完成业务逻辑的单元测试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 21:45:00