2012-02-01 14 views
19

Webサービスを呼び出すコードを書いています。応答を読み込んで何かします。私のコードは次のように名目上になります。私は実際に任意のカスタム操作をしていますCでのHTTPリクエストのユニットテスト#

string body = CreateHttpBody(regularExpression, strategy); 

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_url); 
request.Method = "POST"; 
request.ContentType = "text/plain; charset=utf-8"; 

using (Stream requestStream = request.GetRequestStream()) 
{ 
    requestStream.Write(Encoding.UTF8.GetBytes(body), 0, body.Length); 
    requestStream.Flush(); 
} 

using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) 
{ 
    byte[] data = new byte[response.ContentLength]; 

    using (Stream stream = response.GetResponseStream()) 
    { 
     int bytesRead = 0; 

     while (bytesRead < data.Length) 
     { 
      bytesRead += stream.Read(data, bytesRead, data.Length - bytesRead); 
     } 
    } 

    return ExtractResponse(Encoding.UTF8.GetString(data)); 
} 

部分だけはExtractResponseCreateHttpBody方法です。しかし、それらのメソッドを単体テストするだけでは、間違っていると感じ、コードの残りが正しく一緒になることを願っています。代わりにHTTPリクエストを傍受して模擬データを送る方法はありますか?

EDITこの情報は最新ではありません。ライブラリのSystem.Net.Http.HttpClientを使用すると、この種のコードを作成する方がずっと簡単です。

+0

webserver _を正しく設定して、テストしたいものを設定して、 '\ Windows \ System32 \ drivers \ etc \ hosts'ファイルを変更して、そのサーバーにリクエストを"リダイレクト "することができます。 – ordag

+0

関連:https://stackoverflow.com/q/9823039/12484 –

答えて

14

コードでは、同じメソッドでオブジェクトを作成するため、HttpWebRequestへの呼び出しを代行受信することはできません。別のオブジェクトでHttpWebRequestを作成させる場合は、モックオブジェクトを渡してテストに使用できます。だからではなく、本の

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_url); 

使用この:あなたのユニットテストで

IHttpWebRequest request = this.WebRequestFactory.Create(_url); 

は、あなたがモックオブジェクトを作成しますWebRequestFactoryに渡すことができます。

さらに、あなたは別の機能であなたのストリーム読み出しコードを分割することができます。

using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) 
{ 
    byte[] data = ReadStream(response.GetResponseStream()); 
    return ExtractResponse(Encoding.UTF8.GetString(data)); 
} 

これは別にReadStream()テストすることが可能となります。

さらに統合テストを行うには、テストデータを返す独自のHTTPサーバーを設定し、そのサーバーのURLをメソッドに渡すことができます。

+1

HttpWebRequestオブジェクトとHttpWebResponseオブジェクトをモックしようとMolesとMoqを試した後、これを行うことはできないと結論づけなければなりません。効果的なアプローチ。 – Ceilingfish

6

おそらく、実際のHTTPリクエストに弱く結合させるために、コードをリファクタリングすることから始めます。今、このコードは非常に多くのことをするようです。

これは抽象化を導入することによって行うことができます。

public interface IDataRetriever 
{ 
    public byte[] RetrieveData(byte[] request); 
} 

は今、あなたはユニットテストしようとしているクラスは、コントロールのデザインパターンの反転を使用して、実際のHTTPリクエストから切り離すことができます

public class ClassToTest 
{ 
    private readonly IDataRetriever _dataRetriever; 
    public Foo(IDataRetriever dataRetriever) 
    { 
     _dataRetriever = dataRetriever; 
    } 

    public string MethodToTest(string regularExpression, string strategy) 
    { 
     string body = CreateHttpBody(regularExpression, strategy); 
     byte[] result = _dataRetriever.RetrieveData(Encoding.UTF8.GetBytes(body)); 
     return ExtractResponse(Encoding.UTF8.GetString(result)); 
    } 
} 

実際のHTTPリクエストを処理することはもはやClassToTestの責任ではありません。これでデカップリングされます。 MethodToTestのテストは簡単な作業になります。

そして、最後の部分は明らかに我々が導入している抽象化の実装を持つことです。

public class MyDataRetriever : IDataRetriever 
{ 
    private readonly string _url; 
    public MyDataRetriever(string url) 
    { 
     _url = url; 
    } 

    public byte[] RetrieveData(byte[] request) 
    { 
     using (var client = new WebClient()) 
     { 
      client.Headers[HttpRequestHeader.ContentType] = "text/plain; charset=utf-8"; 
      return client.UploadData(_url, request); 
     } 
    } 
} 

あなたは、あなたの実際の内ClassToTestクラスのコンストラクタにMyDataRetrieverインスタンスを注入するためにあなたの好きなDIフレームワークを構成することができ応用。

+1

私はあなたの要点を見ることができますが、このコードが置かれているクラスはHTTPデータ検索機構として設計されています。リクエストを処理するために使用しているコードが整形式であることをテストしたいので、HTTPコードを抽象化すれば、テストする部分を正確に抽象化しています。 – Ceilingfish

+2

@Ciilingfish、いいえ、あなたは間違いなくHttpWebRequestとHttpWebResponseクラスをテストしたくありません。それらは既にMicrosoftによって広範にテストされています。あなたがテストしたいのは、あなたのメソッドが(あなたに提供され、動作することが期待される)いくつかのブラックボックスに正しい入力を提供し、それが期待どおりのフォーマットに変換されることです。それは基本的にあなたの方法がしていることです。とにかく、このレベルの抽象化がなければ、それらのクラスを模擬することはできず、単体テストではなく統合テストが行​​われます。 –

+3

本当に、私はそれらのクラスをテストしたくないので、それらのクラスの_usage_をテストしたいと思います。 HTTPリクエストを送受信するコードは完全に隠されているわけではないので、要求からの応答を正常に読み取るためには自分のコードが正しいかどうかに依存します。 – Ceilingfish

4

HttpWebRequestとHttpWebResponseを取り除くのが面倒になったり、 "外部"からコードを呼び出す受け入れテストでコードをテストする必要がある場合は、おそらく偽のサービスを作成することが最良の方法です行く。

実際には、これを支援するためにMockHttpServerというオープンソースライブラリを作成しました。これは、HTTP経由で通信する外部サービスをすべて簡単に模倣することを簡単にしています。

RestSharpでAPIエンドポイントを呼び出すためにRestSharpを使用する例ですが、HttpWebRequestも同様に機能します。

using (new MockServer(3333, "/api/customer", (req, rsp, prm) => "Result Body")) 
{ 
    var client = new RestClient("http://localhost:3333/"); 
    var result = client.Execute(new RestRequest("/api/customer", Method.GET)); 
} 

あり、それを使用するために利用できるすべてのオプションを通過GitHubのページでかなり詳細なreadmeファイルがあり、ライブラリ自体はNuGetを通じて利用可能です。

+0

私はこれを行うのに本当に便利なhttps://github.com/unosquare/embedioを見つけました – Ceilingfish

+0

@Ceilingfishプロジェクトはクールだと思っていますが、単純にいくつかの回答を嘲笑しすぎているようです。これはウェブサーバー全体のライブラリであり、少し複雑です。 –

2

HttpClient(公式ポータブルhttpクライアントライブラリ)に移動していただければ、MockHttpと呼ばれることがあるライブラリーを書きました。さまざまな属性を使用して一致したリクエストに対する応答を提供できる流暢なAPIを提供します。

関連する問題