web-dev-qa-db-ja.com

ASP.NET Web API HttpClientのスタブまたはモック

プロジェクトで新しいWeb APIビットを使用していますが、リクエストにクライアント証明書を追加する必要があるため、通常のHttpMessageRequestを使用できないことがわかりました。その結果、私はHttpClientを使用しています(そのため、WebRequestHandlerを使用できます)。これは、少なくともRhino Mocksにとってスタブ/モックフレンドリーではないことを除いて、すべてうまく機能します。

通常、代わりに使用するHttpClientの周りにラッパーサービスを作成しますが、ラップする必要のあるメソッドが多数あるため、可能であればこれを避けたいと思います。私は何かが欠けていることを望んでいます—HttpClientをスタブする方法について何か提案はありますか?

28
Erick T

私はMoqを使用しており、HttpClientをスタブ化できます。これはRhino Mockでも同じだと思います(私は自分で試したことはありません)。 HttpClientをスタブしたい場合は、以下のコードが機能するはずです。

var stubHttpClient = new Mock<HttpClient>();
ValuesController controller = new ValuesController(stubHttpClient.Object);

私が間違っていたら訂正してください。ここで言及しているのは、HttpClient内のメンバーをスタブ化することだと思います。

最も一般的な分離/モックオブジェクトフレームワークでは、非仮想メンバーでスタブ/セットアップを実行できません。たとえば、次のコードは例外をスローします

stubHttpClient.Setup(x => x.BaseAddress).Returns(new Uri("some_uri");

また、多くのHttpClientメンバーをラップするため、ラッパーの作成を避けたいとも述べました。多くのメソッドをラップする必要がある理由は明らかではありませんが、必要なメソッドのみを簡単にラップできます。

例えば ​​:

public interface IHttpClientWrapper  {   Uri BaseAddress { get;  }     }

public class HttpClientWrapper : IHttpClientWrapper
{
   readonly HttpClient client;

   public HttpClientWrapper()   {
       client = new HttpClient();
   }

   public Uri BaseAddress   {
       get
       {
           return client.BaseAddress;
       }
   }
}

他にも役立つと思われるオプション(たくさんの例があるので、コードは記述しません)Microsoft Moles Framework http://research.Microsoft.com/en-us/projects/moles/ Microsoft Fakes:(VS2012 Ultimateを使用している場合) http://msdn.Microsoft.com/en-us/library/hh549175.aspx

11
Spock

@Rajによってすでに提示されている優れたアイデアの代わりに、一歩下がってHttpMessageHandlerをモック/偽造することが可能かもしれません。

HttpClientを必要とするクラスを、コンストラクターの依存関係注入パラメーターとして受け入れるようにすると、単体テスト時に、独自のHttpClientで注入されたHttpMessageHandlerを渡すことができます。この単純なクラスには、次のように実装する必要がある抽象メソッドが1つだけあります。

public class FakeHttpMessageHandler : HttpMessageHandler
    {
    public HttpRequestMessage RequestMessage { get; private set; }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
        RequestMessage = request;
        return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK));
        }
    }

私の簡単な例では、後で検査するためにHttpRequestMessageをパブリックプロパティに保存し、HTTP 200(OK)を返しますが、必要な結果を設定するコンストラクターを追加することでこれを強化できます。

このクラスは次のように使用します。

public void foo()
    {
    //Arrange
    var fakeHandler = new FakeHttpMessageHandler();
    var client = new HttpClient(fakeHandler);
    var SUT = new ClassUnderTest(client);

    //Act
    SUT.DomSomething();

    //Assert
    fakeHandler.RequestMessage.Method.ShouldEqual(HttpMethod.Get); // etc...
    }

この方法には制限があります。たとえば、複数のリクエストを作成するメソッドや、複数のHttpClientsを作成する必要があるメソッドでは、偽のハンドラーが複雑になりすぎる可能性があります。ただし、単純なケースでは検討する価値があります。

62
Tim Long

数か月前に MockHttp というライブラリをリリースしました。流暢な(拡張可能な)APIを備えたカスタムHttpMessageHandlerを使用します。モックされたハンドラー(またはHttpClient)をサービスクラスに挿入すると、構成されたとおりに応答します。

以下に基本的な使い方を示します。 WhenメソッドとRespondメソッドには、カスタムロジックの実行など、多数のオーバーロードがあります。 GitHubページのドキュメント では、さらに詳細に説明しています。

var mockHttp = new MockHttpMessageHandler();

// Setup a respond for the user api (including a wildcard in the URL)
mockHttp.When("http://localhost/api/user/*")
        .Respond("application/json", "{'name' : 'Test McGee'}"); // Respond with JSON

// Inject the handler or client into your application code
var client = new HttpClient(mockHttp);

var response = async client.GetAsync("http://localhost/api/user/1234");
// or without async: var response = client.GetAsync(...).Result;

var json = await response.Content.ReadAsStringAsync();

// No network connection required
Console.Write(json); // {'name' : 'Test McGee'}
38
Richard Szalay