自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

ASP.NET Core 單元測(cè)試之如何 Mock HttpClient.GetStringAsync()

開(kāi)發(fā) 前端
在 ASP.NET Core 單元測(cè)試中模擬HttpClient.GetStringAsync() 的技巧。如果按正常思路像這樣去 Mock HttpClient.GetStringAsync()。

 [[398893]]

本文轉(zhuǎn)載自微信公眾號(hào)「汪宇杰博客」,作者汪宇杰。轉(zhuǎn)載本文請(qǐng)聯(lián)系汪宇杰博客公眾號(hào)。

在 ASP.NET Core 單元測(cè)試中模擬HttpClient.GetStringAsync() 的技巧。

問(wèn)題

下面這個(gè)代碼

  1. var html = await _httpClient.GetStringAsync(sourceUrl); 

如果按正常思路像這樣去 Mock HttpClient.GetStringAsync()

  1. var httpClientMock = new Mock<HttpClient>(); 
  2. httpClientMock 
  3.     .Setup(p => p.GetStringAsync(It.IsAny<string>())) 
  4.     .Returns(Task.FromResult("...")); 

Moq 框架就會(huì)爆

Exception

  1. System.NotSupportedException : Unsupported expression: p => p.GetStringAsync(It.IsAny())Non-overridable members (here: HttpClient.GetStringAsync) may not be used in setup / verification expressions. 

解決方法

我們需要 Mock HttpClient 底層使用的 HttpMessageHandler 而不是 HttpClient

  1. var handlerMock = new Mock<HttpMessageHandler>(); 
  2. var magicHttpClient = new HttpClient(handlerMock.Object); 

然后我花了 9.96 分鐘研究了 HttpClient.GetStringAsync() 的源代碼,發(fā)現(xiàn)它最終調(diào)用的是 SendAsync() 方法

  1. private async Task<string> GetStringAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken) 
  2.     // ... 
  3.     response = await base.SendAsync(request, cts.Token).ConfigureAwait(false); 
  4.     // ... 

源代碼位置:https://source.dot.net/#System.Net.Http/System/Net/Http/HttpClient.cs,170

因此,我們的 Mock Setup 如下:

  1. handlerMock 
  2.     .Protected() 
  3.     .Setup<Task<HttpResponseMessage>>( 
  4.         "SendAsync"
  5.         ItExpr.IsAny<HttpRequestMessage>(), 
  6.         ItExpr.IsAny<CancellationToken>() 
  7.     ) 
  8.     .ReturnsAsync(new HttpResponseMessage 
  9.     { 
  10.         StatusCode = HttpStatusCode.OK, 
  11.         Content = new StringContent("the string you want to return"
  12.     }) 
  13.     .Verifiable(); 

現(xiàn)在 Mock 就能運(yùn)行成功了!

最后附上完整的 UT 代碼供參考:

  1. using System.Net; 
  2. using System.Net.Http; 
  3. using System.Threading; 
  4. using System.Threading.Tasks; 
  5. using Microsoft.Extensions.Logging; 
  6. using Moq; 
  7. using Moq.Protected; 
  8. using NUnit.Framework; 
  9.  
  10. namespace Moonglade.Pingback.Tests 
  11.     [TestFixture] 
  12.     public class PingSourceInspectorTests 
  13.     { 
  14.         private MockRepository _mockRepository; 
  15.  
  16.         private Mock<ILogger<PingSourceInspector>> _mockLogger; 
  17.         private Mock<HttpMessageHandler> _handlerMock; 
  18.         private HttpClient _magicHttpClient; 
  19.  
  20.         [SetUp] 
  21.         public void SetUp() 
  22.         { 
  23.             _mockRepository = new(MockBehavior.Default); 
  24.             _mockLogger = _mockRepository.Create<ILogger<PingSourceInspector>>(); 
  25.             _handlerMock = _mockRepository.Create<HttpMessageHandler>(); 
  26.         } 
  27.  
  28.         private PingSourceInspector CreatePingSourceInspector() 
  29.         { 
  30.             _magicHttpClient = new(_handlerMock.Object); 
  31.             return new(_mockLogger.Object, _magicHttpClient); 
  32.         } 
  33.  
  34.         [Test] 
  35.         public async Task ExamineSourceAsync_StateUnderTest_ExpectedBehavior() 
  36.         { 
  37.             string sourceUrl = "https://996.icu/work-996-sick-icu"
  38.             string targetUrl = "https://greenhat.today/programmers-special-gift"
  39.  
  40.             _handlerMock 
  41.                 .Protected() 
  42.                 .Setup<Task<HttpResponseMessage>>( 
  43.                     "SendAsync"
  44.                     ItExpr.IsAny<HttpRequestMessage>(), 
  45.                     ItExpr.IsAny<CancellationToken>() 
  46.                 ) 
  47.                 .ReturnsAsync(new HttpResponseMessage 
  48.                 { 
  49.                     StatusCode = HttpStatusCode.OK, 
  50.                     Content = new StringContent($"<html>" + 
  51.                                                 $"<head>" + 
  52.                                                 $"<title>Programmer's Gift</title>" + 
  53.                                                 $"</head>" + 
  54.                                                 $"<body>Work 996 and have a <a href=\"{targetUrl}\">green hat</a>!</body>" + 
  55.                                                 $"</html>"
  56.                 }) 
  57.                 .Verifiable(); 
  58.             var pingSourceInspector = CreatePingSourceInspector(); 
  59.  
  60.             var result = await pingSourceInspector.ExamineSourceAsync(sourceUrl, targetUrl); 
  61.             Assert.IsFalse(result.ContainsHtml); 
  62.             Assert.IsTrue(result.SourceHasLink); 
  63.             Assert.AreEqual("Programmer's Gift", result.Title); 
  64.             Assert.AreEqual(targetUrl, result.TargetUrl); 
  65.             Assert.AreEqual(sourceUrl, result.SourceUrl); 
  66.         } 
  67.     } 

 

 

責(zé)任編輯:武曉燕 來(lái)源: 汪宇杰博客
相關(guān)推薦

2021-04-26 14:25:39

ASP.NET Cor單元測(cè)試

2009-07-23 16:29:06

ASP.NET單元測(cè)試

2009-07-24 11:33:12

MVC單元測(cè)試ASP.NET

2024-07-29 12:12:59

2009-08-21 16:09:04

HttpContextPath屬性

2017-03-23 16:02:10

Mock技術(shù)單元測(cè)試

2023-07-04 08:26:15

2009-07-28 17:17:19

ASP.NET概述

2021-01-31 22:56:50

FromServiceASP

2021-02-03 13:35:25

ASPweb程序

2021-03-03 22:37:16

MediatR中介者模式

2021-03-10 09:40:43

LamarASP容器

2021-02-28 20:56:37

NCache緩存框架

2021-01-28 22:39:35

LoggerMessa開(kāi)源框架

2021-03-04 11:10:29

容器化Docker虛擬機(jī)

2021-01-07 07:39:07

工具接口 Swagger

2021-11-01 14:52:38

ElasticSear索引SQL

2021-03-17 09:45:31

LazyCacheWindows

2021-02-02 16:19:08

Serilog日志框架

2021-02-06 21:40:13

SignalR通訊TypeScript
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)