2015-09-29 3 views
13

私は、Windows.Web.Http(Windows 10 UAP App)のHttpClientに依存するクラスを持っています。私は単体テストにしたいので、Get-Callが返すべきものをセットアップするためにHttpClientを "模擬"する必要があります。私は手書きで嘲笑されたIHttpFilterとIHttpContentを使ってHttpClientを使って "単純な"ユニットテストを始めました。それは期待どおりに動作していないと私はテストエクスプローラでInvalidCastExceptionを取得します。ユニットテストWindows.Web.Http HttpClientを虚偽のIHttpFilterとIHttpContentで実行すると、MockedHttpFilterがSystem.InvalidCastExceptionをスローします

ユニットテストは次のようになります

[TestMethod] 
    public async Task TestMockedHttpFilter() 
    { 
     MockedHttpContent mockedContent = new MockedHttpContent("Content from MockedHttpContent"); 
     MockedHttpFilter mockedHttpFilter = new MockedHttpFilter(HttpStatusCode.Ok, mockedContent); 

     HttpClient httpClient = new HttpClient(mockedHttpFilter); 
     var resultContentTask = await httpClient.SendRequestAsync(new HttpRequestMessage(HttpMethod.Get, new Uri("http://dontcare.ch"))).AsTask().ConfigureAwait(false); 
     // Test stops here, throwing System.InvalidCastException: Specified cast is not valid 

     // Code not reached... 
     var result = await resultContentTask.Content.ReadAsStringAsync(); 
     Assert.AreEqual("Content from MockedHttpContent", result); 
    } 

IはMockedHttpFilterにIHttpFilterを実装:

public class MockedHttpFilter : IHttpFilter 
{ 
    private HttpStatusCode _statusCode; 
    private IHttpContent _content; 

    public MockedHttpFilter(HttpStatusCode statusCode, IHttpContent content) 
    { 
     _statusCode = statusCode; 
     _content = content; 
    } 

    public IAsyncOperationWithProgress<HttpResponseMessage, HttpProgress> SendRequestAsync(HttpRequestMessage request) 
    { 
     return AsyncInfo.Run<HttpResponseMessage, HttpProgress>((token, progress) => 
     Task.Run<HttpResponseMessage>(()=> 
     { 
      HttpResponseMessage response = new HttpResponseMessage(_statusCode); 
      response.Content = _content; 
      return response; // Exception thrown after return, but not catched by code/debugger... 
     })); 
    } 
} 

IはMockedHttpContentにIHttpContentを実装:

public class MockedHttpContent : IHttpContent 
{ 
    private string _contentToReturn; 

    public MockedHttpContent(string contentToReturn) 
    { 
     _contentToReturn = contentToReturn; 
    } 

    public HttpContentHeaderCollection Headers 
    { 
     get 
     { 
      return new HttpContentHeaderCollection(); 
     } 
    } 

    public IAsyncOperationWithProgress<string, ulong> ReadAsStringAsync() 
    { 
     return AsyncInfo.Run<string, ulong>((token, progress) => Task.Run<string>(() => 
     { 
      return _contentToReturn; 
     })); 
    } 
} 

エラーをテストエクスプローラで結果ビュー:

Test Name: TestMockedHttpFilter 
Test FullName: xxx.UnitTests.xxxHttpClientUnitTests.TestMockedHttpFilter 
Test Source: xxx.UnitTests\xxxHttpClientUnitTests.cs : line 22 
Test Outcome: Failed 
Test Duration: 0:00:00.1990313 

Result StackTrace: 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult() 
    at xxx.UnitTests.xxxHttpClientUnitTests.<TestMockedHttpFilter>d__1.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
Result Message: Test method xxx.UnitTests.xxxHttpClientUnitTests.TestMockedHttpFilter threw exception: 
System.InvalidCastException: Specified cast is not valid. 

最初に、例外がスローされた理由/私が間違っていることをまず確認しないでください。たぶん、誰かが正しい方向に私を指すことができますか、次に何をチェック/テストするかをヒントを与えることができますか?

第2に、HttpClient依存関係(Windows 10 UAP)で単体テストコードを実行するより良い方法がありますか?

+0

問題を解決しましたか?私もこれに興味があります。 – Corcus

+0

残念ながら、そうではありません。高い仕事量、自宅でのストレス、大学でのストレスのために、私は現在私の私的プロジェクトでは仕事をすることができません。 – 1ppCH

+0

これは本当に単体テストの方法ではありませんが、外部の依存関係をラップし、完全に制御できる単体テストコードだけをラップする必要があります。あなたがコントロールできないフレームワークにモックを注入することは、特定のコンポーネントテスト以外は間違っているようです。別の問題は、[TestMethod]の戻り値の型を無効にすべきでないということです。 –

答えて

0

あなたが最も簡単な解決策を使用することになり、この

var resultContentTask = await httpClient.SendRequestAsync(new HttpRequestMessage(HttpMethod.Get, new Uri("http://dontcare.ch"))).AsTask<IAsyncOperationWithProgress<HttpResponseMessage, HttpProgress>>().ConfigureAwait(false); 
+0

ありがとうございました。私はあなたに変更を提案しようとしましたが、これは私にコンパイラエラーを与えます: 'Error \t CS1929 \t 'IAsyncOperationWithProgress 'には 'AsTask'の定義と最適な拡張メソッドオーバーロード 'WindowsRuntimeSystemExtensions.AsTask >(IAsyncActionWithProgress >) 'は、' IAsyncActionWithProgress > 'のタイプのレシーバを必要とします。 – 1ppCH

0

にこの

var resultContentTask = await httpClient.SendRequestAsync(new HttpRequestMessage(HttpMethod.Get, new Uri("http://dontcare.ch"))).AsTask().ConfigureAwait(false); 

を変更httpClient.SendRequestAsync(...)

試してみるの戻り値を一致さAsTaskオーバーロードを使用していないようですHttpClientを嘲笑するこのライブラリ

https://github.com/richardszalay/mockhttp

PM> Install-Package RichardSzalay.MockHttp 

私はまた、ユニットテストは意味がありません。あなたは、あなたが本当にあなたのクラスをテストしていないしているが、代わりにあなたがしようとしているあなたの接続コード

 //Arrange 
     var mockHttp = new MockHttpMessageHandler(); 
     mockHttp.When("http://dontcare.ch") 
      .Respond("application/txt", "Content from MockedHttpContent"); // Respond with content 
     var client = mockHttp.ToHttpClient(); 

     //Act 
     var response = await client.GetAsync("http://dontcare.ch"); 
     var result = await response.Content.ReadAsStringAsync(); 

     //Assert 
     Assert.AreEqual("Content from MockedHttpContent", result); 
1

でそれをテストしましたHttpClientクラスをテストします。私はあなたの質問でテスト中のメソッドを持っていないので、いくつかのことを仮定します。私はあなたが以下のような何かを行うことを想定しています:

public async Task<MyCustomClass> MethodUnderTest() 
{ 
    // ... 

    using (var client = new HttpClient(...)) 
    { 
     // ... 

     var json = response.Content.ReadAsStringAsync(); 
     return JsonConvert.Deserialize<MyCustomClass>(json); 
    } 
} 

このような場合は、その後、あなたはあなたのクラスは、特定の依存関係を受け入れないことを理解する必要があります。あなたはいずれかの外部依存関係が注入されるようにクラスを変更することができますが、それはわずかな過度の可能性があります。あなたのクラスを消費し、あなたのクラスをインスタンス化してHttpClientをあなたに供給しなければならない人が本当に必要ですか?ですから、より良い選択肢は、具体的なクラスの依存関係を模擬することができる模擬フレームワークを使用することです。ほとんどのmockingフレームワークはmockingインタフェースを扱うことができますが(簡単です)、具体的なクラスをモックすることはほとんどできません。

私が使用することを提案するフレームワークはMicrosoft Fakesフレームワークです。 Microsoft FakesはShims(分離)とStubs(Mock)をサポートしています。分離は、具体的なクラスのメンバー呼び出しを制御するために必要なものです。

私の例では、どのメンバーを制御する必要がありますか? HttpResponseMessage.Content_Get

  • HttpContent.ReadAsStringAsync
  • 私はあなたがJsonConvert.Deserialize<T>()メンバーの動作を変更する必要はないと思いますが、あなたは、あなたがしたい場合でし

    1. 。 Microsoft Fakesフレームワークは、最初は少し難しいですが、使い始めてすぐに使えるようになると、使いやすくなります。また、あなたは分離をサポートする他のフレームワークを使用することができます:Telerik
    2. TypeMockアイソレータ
    3. から

      • JustMockを多分他の人が存在し、私は彼らに慣れていませんよ。

    関連する問題