2012-03-19 25 views
1

私のコードがFacebookへのさまざまな接続エラーを処理することを確認するには、接続シミュレーションを行う必要があります。私は500秒、タイムアウトなどをシミュレートできるようにしたい。C#Facebook SDKでHTTPSの代わりにHTTPを使用するように強制できますか?

これを行う最も簡単な方法は、Fiddlerを使用することですが、HTTPSで動作していないようです(私は試してみると403秒かかる)。

デバッギングの目的で、SDKがHTTPSの代わりにHTTPを使用するように強制する方法はありますか?

答えて

4

Facebook C#SDKは、HttpWebRequestとHttpWebResponse全体を嘲笑するシナリオをサポートしています。実際には、ユニットテストで内部的に使用しています。そのため、Facebook C#SDKのすべてのコードが実際に実行され、結果は常に同じになります。 https://github.com/facebook-csharp-sdk/facebook-csharp-sdk/blob/v5/Source/Facebook.Tests/TestExtensions.csこれらのテストをまだv6に移行していないので、v5ブランチでこれらのテストをチェックする必要があります。

v5の場合、保護されたCreateHttpWebRequestメソッドをFacebookClientでオーバーライドする必要があります。

ここでは、インターネットに接続していない場合のv5の例を示します。 HttpWebRequestWrapper、HttpWebResponseWrapper、WebExceptionWrapperの3つの隠しクラスが必要です。

public static void NoInternetConnection(this Mock<Facebook.FacebookClient> facebookClient, out Mock<HttpWebRequestWrapper> mockRequest, out Mock<WebExceptionWrapper> mockWebException) 
    { 
     mockRequest = new Mock<HttpWebRequestWrapper>(); 
     mockWebException = new Mock<WebExceptionWrapper>(); 
     var mockAsyncResult = new Mock<IAsyncResult>(); 

     var request = mockRequest.Object; 
     var webException = mockWebException.Object; 
     var asyncResult = mockAsyncResult.Object; 

     mockRequest.SetupProperty(r => r.Method); 
     mockRequest.SetupProperty(r => r.ContentType); 
     mockRequest.SetupProperty(r => r.ContentLength); 
     mockAsyncResult 
      .Setup(ar => ar.AsyncWaitHandle) 
      .Returns((ManualResetEvent)null); 

     mockWebException 
      .Setup(e => e.GetResponse()) 
      .Returns<HttpWebResponseWrapper>(null); 

     mockRequest 
      .Setup(r => r.GetResponse()) 
      .Throws(webException); 

     mockRequest 
      .Setup(r => r.EndGetResponse(It.IsAny<IAsyncResult>())) 
      .Throws(webException); 

     AsyncCallback callback = null; 

     mockRequest 
      .Setup(r => r.BeginGetResponse(It.IsAny<AsyncCallback>(), It.IsAny<object>())) 
      .Callback<AsyncCallback, object>((c, s) => 
               { 
                callback = c; 
               }) 
      .Returns(() => 
         { 
          callback(asyncResult); 
          return asyncResult; 
         }); 

     var mockRequestCopy = mockRequest; 
     var mockWebExceptionCopy = mockWebException; 

     facebookClient.Protected() 
      .Setup<HttpWebRequestWrapper>("CreateHttpWebRequest", ItExpr.IsAny<Uri>()) 
      .Callback<Uri>(uri => 
           { 
            mockRequestCopy.Setup(r => r.RequestUri).Returns(uri); 
            mockWebExceptionCopy.Setup(e => e.Message).Returns(string.Format("The remote name could not be resolved: '{0}'", uri.Host)); 
           }) 
      .Returns(request); 
    } 

次のようにテストを書くことができます。私たちはHttpWebRequestのとHttpWebResponseの方がはるかに簡単にからかってきたV6で

[Fact] 
    public void SyncWhenThereIsNotInternetConnectionAndFiddlerIsNotOpen_ThrowsWebExceptionWrapper() 
    { 
     var mockFb = new Mock<FacebookClient> { CallBase = true }; 
     Mock<HttpWebRequestWrapper> mockRequest; 
     Mock<WebExceptionWrapper> mockWebException; 

     mockFb.NoInternetConnection(out mockRequest, out mockWebException); 

     Exception exception = null; 

     try 
     { 
      var fb = mockFb.Object; 
      fb.Get(_parameters); 
     } 
     catch (Exception ex) 
     { 
      exception = ex; 
     } 

     mockFb.VerifyCreateHttpWebRequest(Times.Once()); 
     mockRequest.VerifyGetResponse(); 
     mockWebException.VerifyGetReponse(); 

     Assert.IsAssignableFrom<WebExceptionWrapper>(exception); 
    } 

HttpWebRequestWrapperおよびHttpWebReponseWrapperを継承して、カスタムHttpWebRequestおよびHttpWebResponseを作成します。

次に、Facebook C#SDKのデフォルトのhttp Web要求ファクトリを変更します。ここに、デフォルト工場のサンプルがあります。

FacebookClient.SetDefaultHttpWebRequestFactory(uri => new HttpWebRequestWrapper((HttpWebRequest)WebRequest.Create(uri))); 

FacebookクライアントインスタンスごとにHttpWebRequestFactorを変更する場合は、次のコードを使用します。

var fb = new FacebookClient(); 
fb.HttpWebRequestFactory = uri=> new MyHttpWebRequestWrapper(uri); 

注:HttpWebRequestWrapper、HttpWebResponseWrapper、WebExceptionWrapper、FacebookClient.SetDefaultHttpWebRequestFactoryとFacebookClient。HttpWebRequestFactoryには属性[EditorBrowsable(EditorBrowsableState.Never)]があるため、インテリセンスでは表示されないことがあります。

実際にはFacebookのC#sdkテストの一部で、あなたのアプリユニットテストではないと言われるインターネット接続はありません。 sdkは、インターネット接続が存在しない場合、常にWebExceptionWrapperをスローし、アプリケーションユニットテストは実際にWebExceptionWrapper例外を処理し、httpwebrequestとhttpwebresponse全体を嘲笑しないことを保証する必要があります。

+0

ありがとう!それは私が探していたものです。 –

0

私はあなたのコードに抽象化の別のレベルを導入し、その抽象化のコードを実装よりも導入することをお勧めします。例えば。

public interface IFacebookClient { 
    IEnumerable<Friend> GetFriends(); 
} 

public class HttpsClient : IFacebookClient { 
    public IEnumerable<Friend> GetFriends() { 
    // Make a call out to the Facebook API, as per usual 
    }; 
} 

あなたの消費コードでは、次のようなことがあります。

public class ConsumingCode { 
    private IFacebookClient _client; 

    public ConsumingCode(IFacebookClient client) { 
    _client = client; 

    foreach (Friend friend in _client.GetFriends()) { 
     // Do something with each Friend 
    } 
    } 
} 

IoCコンテナを使用している場合は、すべて自動的に配線されます。 Caliburn.MicroのようなMVVMフレームワークもこれをサポートする傾向があります。

ユニットテスト(または手動テスト)に関しては、インターフェイスの実装を変更することができます。

public class Http403Client : IFacebookClient { 
    public IEnumerable<Friend> GetFriends() { 
    throw new HttpException(403, "Forbidden"); 
    } 
} 

明らかにこれは単なるモックアップの例ですが、私はそれはあなたが実装する概念を実証だと思います。

+0

答えてくれてありがとうございますが、ウェブからの「本当の」悪い回答をテストしたいと思います。私のコードは健全に見えますが、私はすでにあなたが提案したものよりも簡単な方法でそれをテストしました。 FacebookのC#ライブラリにはたくさんのコードがありますが、悪いHTTPレスポンスを受け取ったときにコードと一緒にどのように動作するかを確認する必要があります。 –

+0

終わりには、C#ライブラリが返すものに対して、あなたの呼び出しコードがどのように応答するかはまだ変わりません。それが特定の状況の場合 - GetFoo()を呼び出すと、HasFoo()を呼び出した後に何か悪いことが起き、Reset()を呼び出す必要があります。実際の実装にパススルーコールを組み込み、結果に基づいて結果を返す/シナリオに応じて他のものをスローすることができます。しかし、このような相互作用テストは、自動化された単体テストに最適です。 – MrMDavidson

+0

もう一度、ありがとう - 私はあなたの提案に感謝します。しかし、それは私の質問に対する答えではなく、私は自動テストには興味がありません。私は少し制御することができるコンポーネント(C#SDK)をテストする必要があります。私が見ることができる唯一の方法は、コンポーネントにコードを追加することです(つまり、テストを維持する必要がありますコードを "生きている"コンポーネントの中に入れたり、HTTPに対してコンポーネントを動作させたりすることができます(私は一度だけの手動テストで偽の失敗を起こすことがあります)ので、自動テストについて尋ねる人にとっては素晴らしい提案です。 –

関連する問題