本文转载自微信公众号「汪宇杰博客」,作者汪宇杰。转载本文请联系汪宇杰博客公众号。
在 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的详细内容...
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://haodehen.cn/did41575