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# 单元测试HTTP客户端_C#_Unit Testing_Http - Fatal编程技术网

C# 单元测试HTTP客户端

C# 单元测试HTTP客户端,c#,unit-testing,http,C#,Unit Testing,Http,我使用HttpClient编写了以下代码。我是C#新手,希望学习如何对我的HttpClient进行单元测试,但不确定从何开始。这是我的密码: protected override async Task PopulateData() { using (var client = new HttpClient()) { var token = "private token";

我使用HttpClient编写了以下代码。我是C#新手,希望学习如何对我的HttpClient进行单元测试,但不确定从何开始。这是我的密码:

 protected override async Task PopulateData()
        {
            using (var client = new HttpClient())
            {
                var token = "private token";
                var requestUrl = api_url_here;
                var authenticatedRequestUrl = requestUrl + $"{token}";
                var response = await client.GetAsync(authenticatedRequestUrl);
                var stringResult = await response.Content.ReadAsStringAsync();

                // do something
            }
        }
我已经看到很多不同的文章建议使用不同的单元测试方法,但我不确定如何正确使用它们。例如,我在许多网站上看到过这种单元测试模式:

  [Test]
        public async Task MockingHTTP()
        {
            var requestUri = new Uri("");
            var expectedResponse = "Response";
            var mockHandler = new Mock<HttpMessageHandler>();

            mockHandler.Protected()
                .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(),
                ItExpr.IsAny<CancellationToken>())
                .ReturnsAsync(new HttpResponseMessage(Net.HttpStatusCode.OK));

            var httpClient = new HttpClient(mockHandler.Object);
            var result = await httpClient.GetStringAsync(requestUri).ConfigureAwait(false);
            Assert.AreEqual(expectedResponse, result);

            }
        }
[测试]
公共异步任务MockingHTTP()
{
var requestUri=新Uri(“”);
var expectedResponse=“Response”;
var mockHandler=new Mock();
mockHandler.Protected()
.Setup(“SendAsync”,ItExpr.IsAny(),
ItExpr.IsAny())
.ReturnsAsync(新的HttpResponseMessage(Net.HttpStatusCode.OK));
var httpClient=新的httpClient(mockHandler.Object);
var result=await-httpClient.GetStringAsync(requestUri).ConfigureAwait(false);
Assert.AreEqual(预期响应、结果);
}
}

然而,我不知道如何将这种方法应用到我的代码中。为了成功地对HttpClient进行单元测试,是否有人能为我指出正确的方向

进行单元测试时要做的第一件事是识别“正在测试的系统”或SUT。这就是您需要验证的行为。SUT的任何依赖项都应该被模拟,不应该使用真实版本

在本例中,您使用的是HttpClient,但无法在方法中使用其他处理程序。使用不同的处理程序是伪造HttpClient响应的最简单方法。HttpClient通过构造函数接受不同的处理程序。因此,您需要如下调整代码:

public class YourClassName
{
    private readonly HttpMessageHandler _httpMessageHandler;

    public YourClassName(HttpMessageHandler httpMessageHandler)
    {
        _httpMessageHandler = httpMessageHandler;
    }

    protected override async Task PopulateData()
    {
        using (var client = new HttpClient(_httpMessageHandler))
        {
            var token = "private token";
            var requestUrl = api_url_here;
            var authenticatedRequestUrl = requestUrl + $"{token}";
            var response = await client.GetAsync(authenticatedRequestUrl);
            var stringResult = await response.Content.ReadAsStringAsync();

            // do something
        }
    }
}
现在它是可单元测试的,因为您可以模拟HttpMessageHandler。但实现这一点的代码是。考虑到您在使用HttpClient时遇到的其他缺陷,最好一开始就不要使用HttpClient。见:

我的团队所做的是使用。它有一个更好的语法,没有HttpClient所具有的IDisposable的奇怪特性,并且易于单元测试

protected override async Task PopulateData()
{
    var token = "private token";
    var requestUrl = api_url_here;
    var authenticatedRequestUrl = requestUrl + $"{token}";
    var stringResult = authenticatedRequestUrl.
    var response = await authenticatedRequestUrl.GetAsync();
    var stringResult = await response.Content.ReadAsStringAsync();

    // do something
}
然后,单元测试变得简单得多:

[Test]
public async Task PopulateDataTest()
{
    var requestUri = new Uri("SomeUriWithAToken");
    var expectedResponse = "some response body";
    var systemUnderTest = new YourClassName();

    using (var httpTest = new HttpTest())
    {
        httpTest.RespondWith(expectedResponse);
        var result = await systemUnderTest.PopulateData();
        Assert.AreEqual(expectedResponse, result);
        httpTest.ShouldHaveCalled(requestUri);
    }
}

Flurl的文档非常棒。您可以让它返回各种响应,甚至自动将响应反序列化到C#类。

当进行单元测试时,首先要做的是识别“正在测试的系统”或SUT。这就是您需要验证的行为。SUT的任何依赖项都应该被模拟,不应该使用真实版本

在本例中,您使用的是HttpClient,但无法在方法中使用其他处理程序。使用不同的处理程序是伪造HttpClient响应的最简单方法。HttpClient通过构造函数接受不同的处理程序。因此,您需要如下调整代码:

public class YourClassName
{
    private readonly HttpMessageHandler _httpMessageHandler;

    public YourClassName(HttpMessageHandler httpMessageHandler)
    {
        _httpMessageHandler = httpMessageHandler;
    }

    protected override async Task PopulateData()
    {
        using (var client = new HttpClient(_httpMessageHandler))
        {
            var token = "private token";
            var requestUrl = api_url_here;
            var authenticatedRequestUrl = requestUrl + $"{token}";
            var response = await client.GetAsync(authenticatedRequestUrl);
            var stringResult = await response.Content.ReadAsStringAsync();

            // do something
        }
    }
}
现在它是可单元测试的,因为您可以模拟HttpMessageHandler。但实现这一点的代码是。考虑到您在使用HttpClient时遇到的其他缺陷,最好一开始就不要使用HttpClient。见:

我的团队所做的是使用。它有一个更好的语法,没有HttpClient所具有的IDisposable的奇怪特性,并且易于单元测试

protected override async Task PopulateData()
{
    var token = "private token";
    var requestUrl = api_url_here;
    var authenticatedRequestUrl = requestUrl + $"{token}";
    var stringResult = authenticatedRequestUrl.
    var response = await authenticatedRequestUrl.GetAsync();
    var stringResult = await response.Content.ReadAsStringAsync();

    // do something
}
然后,单元测试变得简单得多:

[Test]
public async Task PopulateDataTest()
{
    var requestUri = new Uri("SomeUriWithAToken");
    var expectedResponse = "some response body";
    var systemUnderTest = new YourClassName();

    using (var httpTest = new HttpTest())
    {
        httpTest.RespondWith(expectedResponse);
        var result = await systemUnderTest.PopulateData();
        Assert.AreEqual(expectedResponse, result);
        httpTest.ShouldHaveCalled(requestUri);
    }
}

Flurl的文档非常棒。您可以让它返回各种响应,甚至自动反序列化C#类的响应。

您不知道这是不是“正确”的方法?它起作用了吗?它容易阅读吗?你明白了吗?你在寻找正确的定义是什么?做事没有一种正确的方式(尽管常常有一种完全错误的方式)。在这种情况下,我认为你不需要问我们这是否正确——你可以自己判断。顺便说一句,HttpClient是一个有点特殊的孩子。尽管它实现了IDisposable,但像现在这样使用它并不是一个好主意。见和。相反,我建议使用更易于阅读和测试的方法,并避免这些陷阱。@梅森我对我的问题进行了适当的编辑以进行解释-抱歉,询问这是否是“正确的方法”可能不是最好的方法。我的意思是,我不知道如何使用它或将它应用到我的代码中,但我也不知道从何处开始模拟HttpClient或对其进行单元测试,我一直在寻找一些正确方向的指导来开始。测试模拟实例在任何情况下都是无用的。模拟实例用于构建测试环境,而不是您要测试的任何东西itself@SirRufo不,没用。关键不是测试HttpClient是否正常工作——这是微软的工作。重点是测试
PopulateData
,以确保它正常工作。这只是基本的单元测试——模拟依赖项。你不知道这是不是“正确”的方法?它起作用了吗?它容易阅读吗?你明白了吗?你在寻找正确的定义是什么?做事没有一种正确的方式(尽管常常有一种完全错误的方式)。在这种情况下,我认为你不需要问我们这是否正确——你可以自己判断。顺便说一句,HttpClient是一个有点特殊的孩子。尽管它实现了IDisposable,但像现在这样使用它并不是一个好主意。见和。相反,我建议使用更易于阅读和测试的方法,并避免这些陷阱。@梅森我对我的问题进行了适当的编辑以进行解释-抱歉,询问这是否是“正确的方法”可能不是最好的方法。我的意思是,我不知道如何使用它或将它应用到我的代码中,但我也不知道从何处开始模拟HttpClient或对其进行单元测试,我一直在寻找一些正确方向的指导来开始。测试模拟实例在任何情况下都是无用的。模拟实例用于构建测试环境,而不是您要测试的任何东西itself@SirRufo不,没用。关键不在于测试HttpClient是什么