使用HttpClient进行Http请求的控制器单元测试

3
我需要为这个控制器编写单元测试(最重要的是,我被要求获得代码覆盖率)。
public class MyController : Controller
{
    public async Task<ActionResult> Index()
    {
        ViewBag.Title = "Home Page";
        var httpClient = new HttpClient();
        var json = await httpClient.GetStringAsync(ConfigurationManager.AppSettings["MyCustomAPI"]);
        var tasks = JsonConvert.DeserializeObject<List<MyObject>>(json);
        return View(tasks);
    }
}

我已经花了两天时间阅读有关这个问题的想法,但是我无法理解。

我一直在考虑像这样注入 HttpClient:

    private readonly HttpClient _httpClient;

    public TasksController(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

将HttpClient传递给控制器构造函数可能不是一个好主意。

然后我一直在关注这篇指南,它使用FakeItEasy,但我没能将此解决方案适应我的要求。

我该如何进行测试?


首先,请查看此帖子:https://codereview.stackexchange.com/questions/69950/single-instance-of-reusable-httpclient,了解每次创建新的 HttpClient 相关的信息。其次,您可以将 HttpClient 的工作抽象成一个接口,然后将该接口注入到控制器中,这样您就可以为测试模拟它。 - saarrrr
1个回答

2

将您的http工作提取到一个接口中,并将该接口的实现注入到您的控制器中。

public interface INetworkService {
  Task<List<MyObject>> GetThingsAsync(string api);
}

public class HttpNetworkService : INetworkService {
  private readonly HttpClient Client;
  public HttpNetworkService(HttpClient client) {
    Client = client;
  }

  public Task<List<MyObject>> GetThingsAsync(string api) {
    var json = await Client.GetStringAsync(api);
    return JsonConvert.DeserializeObject<List<MyObject>>(json);
  }
}

public class TestNetworkService : INetworkService {
  public Task<List<MyObject>> GetThingsAsync(string api) {
    return Task.FromResult(new List<MyObject> { /*build out your mock result here*/ });
  }
}

public class MyController : Controller {
  private readonly INetworkService NetworkService;
  public MyController(INetworkService svc) {
    NetworkService = svc;
  }

  public async Task<ActionResult> Index() {
    ViewBag.Title = "Home Page";
    var tasks = await NetworkService.GetThingsAsync(ConfigurationManager.AppSettings["MyCustomAPI"]);
    return View(tasks);
  }
}

现在,当您进行测试时,可以使用测试版本的INetworkService替换原来的服务,这个测试版本不会执行任何网络IO操作。此外,如评论中所述,应共享一个单一的HttpClient而不是一直创建新的实例,该客户端可以注入到真正的INetworkedService实现中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接