Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/258.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在.NETCore2.1中使用Moq模拟新的HttpClientFactory_C#_Unit Testing_Moq_Asp.net Core 2.1_Httpclientfactory - Fatal编程技术网

C# 如何在.NETCore2.1中使用Moq模拟新的HttpClientFactory

C# 如何在.NETCore2.1中使用Moq模拟新的HttpClientFactory,c#,unit-testing,moq,asp.net-core-2.1,httpclientfactory,C#,Unit Testing,Moq,Asp.net Core 2.1,Httpclientfactory,.NET Core 2.1附带了一个名为HttpClientFactory的新工厂,但我不知道如何模拟它来对一些包括REST服务调用的方法进行单元测试 正在使用.NET Core IoC容器注入工厂,该方法所做的是从工厂创建一个新客户端: var client = _httpClientFactory.CreateClient(); 然后使用客户端从REST服务获取数据: var result = await client.GetStringAsync(url); HttpClientFac

.NET Core 2.1附带了一个名为
HttpClientFactory
的新工厂,但我不知道如何模拟它来对一些包括REST服务调用的方法进行单元测试

正在使用.NET Core IoC容器注入工厂,该方法所做的是从工厂创建一个新客户端:

var client = _httpClientFactory.CreateClient();
然后使用客户端从REST服务获取数据:

var result = await client.GetStringAsync(url);

HttpClientFactory的

var mockFactory = new Mock<IHttpClientFactory>();
然后,在执行测试时,可将工厂注入受测的从属系统

如果不希望客户端调用实际端点,则需要创建一个伪委托处理程序来拦截请求

用于伪造请求的处理程序存根示例

public class DelegatingHandlerStub : DelegatingHandler {
    private readonly Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> _handlerFunc;
    public DelegatingHandlerStub() {
        _handlerFunc = (request, cancellationToken) => Task.FromResult(request.CreateResponse(HttpStatusCode.OK));
    }

    public DelegatingHandlerStub(Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> handlerFunc) {
        _handlerFunc = handlerFunc;
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
        return _handlerFunc(request, cancellationToken);
    }
}

这个代码为我抛出了这个异常, System.InvalidOperationException:请求没有关联的配置对象,或者提供的配置为空

因此,在测试方法中包含了这一点,它是有效的

var configuration = new HttpConfiguration();
var request = new HttpRequestMessage();
request.SetConfiguration(configuration);

除了前面介绍如何设置存根的文章外,您还可以使用Moq设置
DelegatingHandler

var clientHandlerMock = new Mock<DelegatingHandler>();
clientHandlerMock.Protected()
    .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
    .ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK))
    .Verifiable();
clientHandlerMock.As<IDisposable>().Setup(s => s.Dispose());

var httpClient = new HttpClient(clientHandlerMock.Object);

var clientFactoryMock = new Mock<IHttpClientFactory>(MockBehavior.Strict);
clientFactoryMock.Setup(cf => cf.CreateClient()).Returns(httpClient).Verifiable();

clientFactoryMock.Verify(cf => cf.CreateClient());
clientHandlerMock.Protected().Verify("SendAsync", Times.Exactly(1), ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>());
var clientHandlerMock=new Mock();
clientHandlerMock.Protected()
.Setup(“sendsync”、ItExpr.IsAny()、ItExpr.IsAny())
.ReturnsAsync(新的HttpResponseMessage(HttpStatusCode.OK))
.可验证();
clientHandlerMock.As().Setup(s=>s.Dispose());
var httpClient=新的httpClient(clientHandlerMock.Object);
var clientFactoryMock=newmock(MockBehavior.Strict);
clientFactoryMock.Setup(cf=>cf.CreateClient()).Returns(httpClient.Verifiable();
验证(cf=>cf.CreateClient());
clientHandlerMock.Protected();

我使用了@Nkosi中的示例,但是使用了
.NET 5
我得到了
HttpConfiguration
所需的Microsoft.AspNet.WebApi.Core
软件包的以下警告

警告NU1701程序包“Microsoft.AspNet.WebApi.Core 5.2.7”被删除 已使用“.NETFramework,版本=v4.6.1”还原, .NETFramework,版本=v4.6.2,.NETFramework,版本=v4.7, .NETFramework,版本=v4.7.1,.NETFramework,版本=v4.7.2, .NETFramework,Version=v4.8'而不是项目目标框架 “net5.0”。此软件包可能与您的项目不完全兼容

不使用
HttpConfiguration
完成示例:

private LoginController GetLoginController()
{
    var expected = "Hello world";
    var mockFactory = new Mock<IHttpClientFactory>();

    var mockMessageHandler = new Mock<HttpMessageHandler>();
    mockMessageHandler.Protected()
        .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
        .ReturnsAsync(new HttpResponseMessage
        {
            StatusCode = HttpStatusCode.OK,
            Content = new StringContent(expected)
        });

    var httpClient = new HttpClient(mockMessageHandler.Object);

    mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(httpClient);

    var logger = Mock.Of<ILogger<LoginController>>();

    var controller = new LoginController(logger, mockFactory.Object);

    return controller;
}
private LoginController GetLoginController()
{
var expected=“Hello world”;
var mockFactory=new Mock();
var mockMessageHandler=new Mock();
mockMessageHandler.Protected()
.Setup(“sendsync”、ItExpr.IsAny()、ItExpr.IsAny())
.ReturnsAsync(新的HttpResponseMessage
{
StatusCode=HttpStatusCode.OK,
内容=新的StringContent(预期)
});
var httpClient=新的httpClient(mockMessageHandler.Object);
mockFactory.Setup(=>wk.CreateClient(It.IsAny())).Returns(httpClient);
var logger=Mock.Of();
var控制器=新的LoginController(记录器,mockFactory.Object);
返回控制器;
}
资料来源:


另一种方法可能是创建一个额外的类,该类将在内部调用服务。这个类很容易被模仿。
这不是对这个问题的直接回答,但它似乎不那么复杂,更易于测试。

当我尝试用Moq做类似的事情时,我从Moq得到了一个错误,不支持扩展方法的设置,这就是为什么我在第一个实例中问这个问题的原因,明天我将试用您的版本。@MauricioAtanache注意,我设置的是实际的接口成员,而不是扩展方法。扩展最终将调用接口方法。如果有人好奇,我在查找可在HttpRequestMessageExtensions中找到的
request.CreateResponse()
的适当引用时遇到问题。我通过将Microsoft.AspNet.WebApi.Core包添加到projectWow中,将其添加到了我的单元测试项目中。多痛苦啊。。。我希望
CreateClient()
方法返回一个接口,而不是具体的HttpClient类型。您应该将
.Returns(client)
更改为
。Returns(()=>newhttpclient(clientHandlerStub))
以防止在第二次调用时返回已处理的
HttpClient
s。
var configuration = new HttpConfiguration();
var request = new HttpRequestMessage();
request.SetConfiguration(configuration);
var clientHandlerMock = new Mock<DelegatingHandler>();
clientHandlerMock.Protected()
    .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
    .ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK))
    .Verifiable();
clientHandlerMock.As<IDisposable>().Setup(s => s.Dispose());

var httpClient = new HttpClient(clientHandlerMock.Object);

var clientFactoryMock = new Mock<IHttpClientFactory>(MockBehavior.Strict);
clientFactoryMock.Setup(cf => cf.CreateClient()).Returns(httpClient).Verifiable();

clientFactoryMock.Verify(cf => cf.CreateClient());
clientHandlerMock.Protected().Verify("SendAsync", Times.Exactly(1), ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>());
private LoginController GetLoginController()
{
    var expected = "Hello world";
    var mockFactory = new Mock<IHttpClientFactory>();

    var mockMessageHandler = new Mock<HttpMessageHandler>();
    mockMessageHandler.Protected()
        .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
        .ReturnsAsync(new HttpResponseMessage
        {
            StatusCode = HttpStatusCode.OK,
            Content = new StringContent(expected)
        });

    var httpClient = new HttpClient(mockMessageHandler.Object);

    mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(httpClient);

    var logger = Mock.Of<ILogger<LoginController>>();

    var controller = new LoginController(logger, mockFactory.Object);

    return controller;
}