我确实找到了一百篇关于如何在 C# 中执行此操作的帖子,但没有一篇关于如何在 VB.Net 中执行此操作的帖子。每次将这些方法转换为 VB.NET 的尝试都失败了。似乎可以归结为 SendAsync 是“受保护的朋友”这一事实,如以下错误图像所示:
如果您看不到图像,我收到的错误是:“HttpMessageHandler.Protected Friend MustOverride Overloads Function SendAsync(request As HttpRequestMessage, candellationToken As CancellationToken) As Task(Of HttpResponseMessage)”在此上下文中无法访问,因为这是“受保护的朋友”。错误号是 BC30390,这会导致非常有用的 Microsoft 错误页面“抱歉,我们没有关于此 Visual Basic 错误的详细信息”。
首先,这是一个跨越多个部门的庞然大物,更改为 C# 不是一个选择。我正在对业务逻辑的一部分进行单元测试,该逻辑从另一个系统调用 API,然后在返回该数据时执行其他代码并返回结果。测试数据不能依赖从外部 API 返回的结果,因此我需要模拟 API 结果以与我的测试数据匹配。这是我尝试测试的 BL 函数部分:
Public Sub New(context As IUSASContext, account As IAccount, configurationManager As IDBConfigurationManager)
_Context = context
_Account = account
_AppSettingsConfigManager = configurationManager
_UserPreferenceHistory = New UserPreferenceHistory(_Context, _Account)
End Sub
Public Async Function GetUserPreferenceResponseData(id As Long, httpClient As HttpClient) As Task(Of UserPreferences)
Dim baseUri = New Uri(AppSettingsHelper.GetValue(AppSettingName.ActivitySummaryApiUri, "", _AppSettingsConfigManager))
Dim userContentReponse = Await httpClient.GetAsync(New Uri(baseUri, "/api/v1/UserContents"))
Dim userContentData = Await userContentReponse.Content.ReadAsStringAsync()
Dim userResponse = Await httpClient.GetAsync(New Uri(baseUri, $"/api/v1/Users/{_Account.CurrentTenant}/{id}"))
Dim userData = Await userResponse.Content.ReadAsStringAsync()
Dim userPreferences As UserPreferences = Newtonsoft.Json.JsonConvert.DeserializeObject(Of UserPreferences)(userData)
userPreferences.SchedulesList = GetUserPreferencesEmailScheduleList()
userPreferences.UserContentsList = Newtonsoft.Json.JsonConvert.DeserializeObject(Of List(Of Opm.Staffing.Models.ActivitySummary.UserContent))(userContentData)
userPreferences.Id = id
Return userPreferences
End Function
首先,我尝试模拟 HttpClient 本身,并设置“GetAsync”函数,但事实证明这是不可能的。快速的网络搜索证明,普遍的共识是模拟 HttpResponseMessage 并设置“SendAsync”。但是,C# 示例显示将“Protected”放在“Setup”关键字之前,如下例示例:
mockHttpMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent("{'name':thecodebuzz,'city':'USA'}"),
});
当我尝试这样做时,出现以下错误:
这是我的单元测试的最新版本:
<TestMethod()> Public Sub GetUserPreferenceResponseData()
'Arrange
Dim methodName = System.Reflection.MethodBase.GetCurrentMethod().Name
Dim asuc As New ActivitySummary.UserContent() With {.UserContentId = 1, .UserContentName = "BB"}
Dim uc As New List(Of ActivitySummary.UserContent) From {asuc}
' the below produces the "Protected Friend" intellesense error
'_HTTPMessageHandlerMock.Setup(Function(x) x.SendAsync(It.IsAny(Of HttpRequestMessage), It.IsAny(Of Threading.CancellationToken))) _
.Returns(New HttpResponseMessage With {.Content = New StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(uc))})
' the below produces the "String not a Delegate Type " intellesense error
_HTTPMessageHandlerMock.Protected().Setup(Function(x) x.SendAsync(It.IsAny(Of HttpRequestMessage), It.IsAny(Of Threading.CancellationToken))) _
.Returns(New HttpResponseMessage With {.Content = New StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(uc))})
Dim _Client = New HttpClient(_HTTPMessageHandlerMock.Object)
Dim userPreferencesBL As New UserPreferencesBL(_Context, _Account, _dbConfigManager)
Dim uid As Integer
'Action
Dim result = userPreferencesBL.GetUserPreferenceResponseData(uid, _Client)
'Assert
Assert.IsNotNull(result, methodName + " returned null, expected User Preferences.")
End Sub
将鼠标悬停在“SendAsync”上会显示我上面提到的错误。
我一直在兜圈子,因为改变一件事会破坏另一件事,而我本以为已经解决了。任何帮助将不胜感激。
这样的东西应该有效:
Dim httpMessageHandlerMock As New Mock(Of HttpMessageHandler)
httpMessageHandlerMock _
.Protected() _ ' Needs Imports Moq.Protected
.Setup(Of Task(Of HttpResponseMessage))(
"SendAsync",
ItExpr.IsAny(Of HttpRequestMessage),
ItExpr.IsAny(Of Threading.CancellationToken)) _
.ReturnsAsync(
New HttpResponseMessage() With
{
.Content = New JsonConvert.SerializeObject(uc))
})
Dim client = New HttpClient(httpMessageHandlerMock.Object)
请注意,正如评论所说,您需要
Imports Moq.Protected
因为否则
Protected
扩展方法和该 API 的其余部分不可用。
您不能使用具有
Protected
访问权限的 lambda 表达式或其他强类型表达式,因为该方法仅对继承类可见,并且测试或 httpMessageHandlerMock
不是从 HttpMessageHandler
继承的。因此,您需要使用字符串 ("SendAsync"
) 来标识要重写的方法,并使用 ItExpr
API 来匹配输入参数。