当前位置: 首页 > 知识库问答 >
问题:

在单元测试中模拟HttpClient

顾乐心
2023-03-14

我在尝试包装我的代码以用于单元测试时遇到了一些问题。问题是。我有接口IHttpHandler:

public interface IHttpHandler
{
    HttpClient client { get; }
}
public class HttpHandler : IHttpHandler
{
    public HttpClient client
    {
        get
        {
            return new HttpClient();
        }
    }
}
public class Connection
{
    private IHttpHandler _httpClient;

    public Connection(IHttpHandler httpClient)
    {
        _httpClient = httpClient;
    }
}
private IHttpHandler _httpClient;

[TestMethod]
public void TestMockConnection()
{
    var client = new Connection(_httpClient);

    client.doSomething();  

    // Here I want to somehow create a mock instance of the http client
    // Instead of the real one. How Should I approach this?     

}

现在很明显,我将在Connection类中有一些方法,这些方法将从my后端检索数据(JSON)。但是,我想为这个类编写单元测试,显然我不想编写针对真实后端的测试,而是一个被嘲弄的测试。我曾尝试谷歌一个很好的答案,但没有很大的成功。我以前可以并且曾经使用过Moq来模拟,但是从来没有在像HttpClient这样的东西上。我该如何处理这个问题?

提前道谢。

共有1个答案

叶鸿煊
2023-03-14

您的接口公开了具体的HttpClient类,因此使用该接口的任何类都与它绑定,这意味着它不能被嘲弄。

HttpClient不从任何接口继承,因此您必须编写自己的接口。我建议一个类似装饰器的模式

public interface IHttpHandler
{
    HttpResponseMessage Get(string url);
    HttpResponseMessage Post(string url, HttpContent content);
    Task<HttpResponseMessage> GetAsync(string url);
    Task<HttpResponseMessage> PostAsync(string url, HttpContent content);
}

您的类将如下所示:

public class HttpClientHandler : IHttpHandler
{
    private HttpClient _client = new HttpClient();

    public HttpResponseMessage Get(string url)
    {
        return GetAsync(url).Result;
    }

    public HttpResponseMessage Post(string url, HttpContent content)
    {
        return PostAsync(url, content).Result;
    }

    public async Task<HttpResponseMessage> GetAsync(string url)
    {
        return await _client.GetAsync(url);
    }

    public async Task<HttpResponseMessage> PostAsync(string url, HttpContent content)
    {
        return await _client.PostAsync(url, content);
    }
}

这种方法的主要问题是,您正在有效地编写一个只调用另一个类中的方法的类,但是您可以创建一个继承HttpClient的类(参见Nkosi的示例,它比我的方法好得多)。如果HttpClient有一个可以模仿的接口,生活就会轻松得多,但不幸的是,它没有。

然而,这个例子并不是金票。IHttpHandler仍然依赖于HttpResponseMessage,它属于System.net.http命名空间,因此,如果您确实需要HttpClient以外的其他实现,则必须执行某种映射,将它们的响应转换为HttpResponseMessage对象。当然,只有在需要使用IHttpHandler的多个实现时,这才是一个问题,但看起来并不是这样做的。这不是世界末日,而是需要考虑的问题。

无论如何,您可以简单地模拟IHttpHandler,而不必担心具体的HttpClient类,因为它已经被抽象掉了。

我建议测试非异步方法,因为这些方法仍然调用异步方法,但不必担心单元测试异步方法,请参阅此处

 类似资料:
  • 问题内容: 我正在为启动a 并使用返回的诺言执行一些逻辑的控制器编写单元测试。我可以测试触发$ modal的父控制器,但是我一生无法弄清楚如何模拟成功的诺言。 我尝试了多种方法,包括使用和强制履行承诺。但是,我得到的最接近的结果是与本 SO帖子中的最后一个答案相似的东西。 我已经在“旧的” 模式中看到了几次这样的问题。在“新” 模式下,我找不到太多的方法。 一些指针将不胜感激。 为了说明问题,我使

  • 在类中,我有一个函数,它调用另一个函数: 我要使用对进行单元测试: 我的实现代码抛出并不容易,我如何使测试代码模拟一个RuntimeException&抛出它呢? (除了纯JUnit之外,我正在考虑使用Mockito,但不确定如何抛出RuntimeException)

  • 我面临一个问题,而嘲笑jUnit测试的东西。 情况如下: 类A实现了来自第三方jar的接口,并且需要实现method1。除了method1之外,A还包含method2,它是从method1调用的。method2本身调用一些外部服务。 我想单元测试方法1。 方法1接受输入,比如X。X有一个包裹在里面的输入变量,比如var1。var1由方法1中的逻辑使用,方法1在X中设置另一个变量,比如var2。 所

  • 问题内容: 我正在使用RestTemplate 方法发布到端点。在我的测试文件中,我正在测试POST方法。但是用我目前的测试,我得到了POST请求。在测试文件中发出POST请求时,我需要模拟API的帮助 这是我的主文件 这是我的测试文件 问题答案: 您正在测试DataTestRepo类内部的逻辑,因此您不应模拟它。RestTemplate是DataTestRepo内部的一个依赖项,因此这正是您需要

  • 遇到了另一个常见的问题,同时为Spring Batch编写单元测试和集成测试组件是如何模拟域对象。一个很好的例子是StepExecutionListener,如下所示: public class NoWorkFoundStepExecutionListener extends StepExecutionListenerSupport { public ExitStatus afterSte

  • 我有一个调用流api的异步函数。为这个函数编写单元测试的最佳方法是什么?必须模拟api响应。 我尝试使用aiounittest,并使用unittest的mock。但是这调用了实际的api,而不是得到模拟的响应。也尝试pytest.mark.asyncio注释,但这一直给我的错误-协程从未等待。我已经验证pyest-asyncio已经安装。 我正在使用VS代码和Python 3.6.6 以下是相关的