1. ホーム
  2. c#

[解決済み] ユニットテストでのHttpClientのモック化

2022-04-20 08:12:30

質問

ユニットテストで使用するためにコードをラップしようとすると、いくつかの問題が発生します。その問題とは、次のようなものです。私はインターフェイス IHttpHandler :

public interface IHttpHandler
{
    HttpClient client { get; }
}

そして、それを利用したクラス。 HttpHandler :

public class HttpHandler : IHttpHandler
{
    public HttpClient client
    {
        get
        {
            return new HttpClient();
        }
    }
}

そして、その後に Connection クラスで、クライアントの実装を注入するために simpleIOC を使用しています。

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 クラスは、私のバックエンドからデータ (JSON) を取得します。しかし、このクラスのユニットテストを書きたいのですが、明らかに本物のバックエンドに対するテストではなく、モックされたものに対するテストを書きたいと思っています。これに対する良い答えをググってみましたが、あまり成功しませんでした。以前、Moqを使ってモックを作ったことがありますが、次のようなものには使ったことがありません。 HttpClient . この問題にどのようにアプローチすればよいのでしょうか?

どのように解決するのですか?

あなたのインターフェイスは具体的な 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);
    }
}

これらすべてにおいて重要なのは HttpClientHandler は自分自身の HttpClient を実装したクラスを複数作成することができます。 IHttpHandler をさまざまな方法で作成します。

この方法の主な問題は、事実上、他のクラスのメソッドを呼び出すだけのクラスを書いていることです。 を継承しています。 からの HttpClient (参照 Nkosiの例 私のやり方よりずっといい方法です)。もし HttpClient はモックできるインターフェイスを持っていますが、残念ながらそれはありません。

この例は ではない しかし、その金字塔は IHttpHandler に依存しています。 HttpResponseMessage に属している。 System.Net.Http 名前空間以外の実装が必要な場合、その実装は HttpClient に変換するために、何らかのマッピングを行う必要があります。 HttpResponseMessage オブジェクトを作成します。これはもちろん、以下のような問題だけです。 複数の実装を使用する必要がある場合 IHttpHandler が、そうではなさそうなので、この世の終わりというわけではありませんが、考えておく必要があります。

とにかく、単純にモック IHttpHandler を気にすることなく、具体的な HttpClient クラスが抽象化されているためです。

をテストすることをお勧めします。 非同期 これらは非同期メソッドを呼び出しますが、非同期メソッドのユニットテストを気にする必要はありません。 こちら