ASP.NET Core 单元测试之如何 Mock HttpClient.GetStringAsync()

2025-05-29 0 67

ASP.NET Core 单元测试之如何 Mock HttpClient.GetStringAsync()

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

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

问题

下面这个代码

  1. varhtml=await_httpClient.GetStringAsync(sourceUrl);

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

  1. varhttpClientMock=newMock<HttpClient>();
  2. httpClientMock
  3. .Setup(p=>p.GetStringAsync(It.IsAny<string>()))
  4. .Returns(Task.FromResult("…"));

Moq 框架就会爆

Exception

  1. System.NotSupportedException:Unsupportedexpression:p=>p.GetStringAsync(It.IsAny())Non-overridablemembers(here:HttpClient.GetStringAsync)maynotbeusedinsetup/verificationexpressions.

解决方法

我们需要 Mock HttpClient 底层使用的 HttpMessageHandler 而不是 HttpClient

  1. varhandlerMock=newMock<HttpMessageHandler>();
  2. varmagicHttpClient=newHttpClient(handlerMock.Object);

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

  1. privateasyncTask<string>GetStringAsyncCore(HttpRequestMessagerequest,CancellationTokencancellationToken)
  2. {
  3. //…
  4. response=awaitbase.SendAsync(request,cts.Token).ConfigureAwait(false);
  5. //…
  6. }

源代码位置: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(newHttpResponseMessage
  9. {
  10. StatusCode=HttpStatusCode.OK,
  11. Content=newStringContent("thestringyouwanttoreturn")
  12. })
  13. .Verifiable();

现在 Mock 就能运行成功了!

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

  1. usingSystem.Net;
  2. usingSystem.Net.Http;
  3. usingSystem.Threading;
  4. usingSystem.Threading.Tasks;
  5. usingMicrosoft.Extensions.Logging;
  6. usingMoq;
  7. usingMoq.Protected;
  8. usingNUnit.Framework;
  9. namespaceMoonglade.Pingback.Tests
  10. {
  11. [TestFixture]
  12. publicclassPingSourceInspectorTests
  13. {
  14. privateMockRepository_mockRepository;
  15. privateMock<ILogger<PingSourceInspector>>_mockLogger;
  16. privateMock<HttpMessageHandler>_handlerMock;
  17. privateHttpClient_magicHttpClient;
  18. [SetUp]
  19. publicvoidSetUp()
  20. {
  21. _mockRepository=new(MockBehavior.Default);
  22. _mockLogger=_mockRepository.Create<ILogger<PingSourceInspector>>();
  23. _handlerMock=_mockRepository.Create<HttpMessageHandler>();
  24. }
  25. privatePingSourceInspectorCreatePingSourceInspector()
  26. {
  27. _magicHttpClient=new(_handlerMock.Object);
  28. returnnew(_mockLogger.Object,_magicHttpClient);
  29. }
  30. [Test]
  31. publicasyncTaskExamineSourceAsync_StateUnderTest_ExpectedBehavior()
  32. {
  33. stringsourceUrl="https://996.icu/work-996-sick-icu";
  34. stringtargetUrl="https://greenhat.today/programmers-special-gift";
  35. _handlerMock
  36. .Protected()
  37. .Setup<Task<HttpResponseMessage>>(
  38. "SendAsync",
  39. ItExpr.IsAny<HttpRequestMessage>(),
  40. ItExpr.IsAny<CancellationToken>()
  41. )
  42. .ReturnsAsync(newHttpResponseMessage
  43. {
  44. StatusCode=HttpStatusCode.OK,
  45. Content=newStringContent($"<html>"+
  46. $"<head>"+
  47. $"<title>Programmer'sGift</title>"+
  48. $"</head>"+
  49. $"<body>Work996andhavea<ahref=\\"{targetUrl}\\">greenhat</a>!</body>"+
  50. $"</html>")
  51. })
  52. .Verifiable();
  53. varpingSourceInspector=CreatePingSourceInspector();
  54. varresult=awaitpingSourceInspector.ExamineSourceAsync(sourceUrl,targetUrl);
  55. Assert.IsFalse(result.ContainsHtml);
  56. Assert.IsTrue(result.SourceHasLink);
  57. Assert.AreEqual("Programmer'sGift",result.Title);
  58. Assert.AreEqual(targetUrl,result.TargetUrl);
  59. Assert.AreEqual(sourceUrl,result.SourceUrl);
  60. }
  61. }
  62. }

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

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 ASP.NET Core 单元测试之如何 Mock HttpClient.GetStringAsync() https://www.kuaiidc.com/97322.html

相关文章

发表评论
暂无评论