好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

ASP.NET Core 单元测试之如何 Mock HttpClient.GetStringAsyn

 

本文转载自微信公众号「汪宇杰博客」,作者汪宇杰。转载本文请联系汪宇杰博客公众号。

在 ASP.NET Core 单元测试 中模拟HttpClient.GetStringAsync() 的技巧。

问题

 

下面这个代码

var html = await _httpClient.GetStringAsync(sourceUrl); 

如果按正常思路像这样去 Mock HttpClient.GetStringAsync()

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

Moq 框架就会爆

 

Exception

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

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

然后我花了 9.96 分钟研究了 HttpClient.GetStringAsync() 的源代码,发现它最终调用的是 SendAsync() 方法

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

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

因此,我们的 Mock Setup 如下:

handlerMock      .Protected()      .Setup<Task<HttpResponseMessage>>(           "SendAsync" ,          ItExpr.IsAny<HttpRequestMessage>(),          ItExpr.IsAny<CancellationToken>()      )      .ReturnsAsync(new HttpResponseMessage      {          StatusCode = HttpStatusCode.OK,          Content = new StringContent( "the string you want to return" )      })      .Verifiable(); 

现在 Mock 就能运行成功了!

最后附上完整的 UT 代码供参考:

using System.Net;  using System.Net.Http;  using System.Threading;  using System.Threading.Tasks;  using Microsoft.Extensions.Logging;  using Moq;  using Moq.Protected;  using NUnit.Framework;    namespace Moonglade.Pingback.Tests  {      [TestFixture]       public  class PingSourceInspectorTests      {          private MockRepository _mockRepository;            private Mock<ILogger<PingSourceInspector>> _mockLogger;          private Mock<HttpMessageHandler> _handlerMock;          private HttpClient _magicHttpClient;            [SetUp]           public  void SetUp()          {              _mockRepository = new(MockBehavior. Default );              _mockLogger = _mockRepository. Create <ILogger<PingSourceInspector>>();              _handlerMock = _mockRepository. Create <HttpMessageHandler>();          }            private PingSourceInspector CreatePingSourceInspector()          {              _magicHttpClient = new(_handlerMock.Object);               return  new(_mockLogger.Object, _magicHttpClient);          }            [Test]           public  async Task ExamineSourceAsync_StateUnderTest_ExpectedBehavior()          {              string sourceUrl =  "https://996.icu/work-996-sick-icu" ;              string targetUrl =  "https://greenhat.today/programmers-special-gift" ;                _handlerMock                  .Protected()                  .Setup<Task<HttpResponseMessage>>(                       "SendAsync" ,                      ItExpr.IsAny<HttpRequestMessage>(),                      ItExpr.IsAny<CancellationToken>()                  )                  .ReturnsAsync(new HttpResponseMessage                  {                      StatusCode = HttpStatusCode.OK,                      Content = new StringContent($ "<html>"  +                                                  $ "<head>"  +                                                  $ "<title>Programmer's Gift</title>"  +                                                  $ "</head>"  +                                                  $ "<body>Work 996 and have a <a href=\"{targetUrl}\">green hat</a>!</body>"  +                                                  $ "</html>" )                  })                  .Verifiable();              var pingSourceInspector = CreatePingSourceInspector();                var result = await pingSourceInspector.ExamineSourceAsync(sourceUrl, targetUrl);              Assert.IsFalse(result.ContainsHtml);              Assert.IsTrue(result.SourceHasLink);              Assert.AreEqual( "Programmer's Gift" , result.Title);              Assert.AreEqual(targetUrl, result.TargetUrl);              Assert.AreEqual(sourceUrl, result.SourceUrl);          }      }  } 

原文链接:https://mp.weixin.qq.com/s/Ljst8xxnC0iURU4Ev6RSpQ

dy("nrwz");

查看更多关于ASP.NET Core 单元测试之如何 Mock HttpClient.GetStringAsyn的详细内容...

  阅读:69次