メソッドをHttpClient
使用SendAsync
してすべてを実行するため、メソッドを実行してモックするHTTP Requests
ことができますoverride SendAsync
HttpClient
。
そのラップを作成HttpClient
するにはinterface
、以下のようなもの
public interface IServiceHelper
{
HttpClient GetClient();
}
次にinterface
、サービスでの依存性注入に上記を使用し、以下のサンプル
public class SampleService
{
private readonly IServiceHelper serviceHelper;
public SampleService(IServiceHelper serviceHelper)
{
this.serviceHelper = serviceHelper;
}
public async Task<HttpResponseMessage> Get(int dummyParam)
{
try
{
var dummyUrl = "http://www.dummyurl.com/api/controller/" + dummyParam;
var client = serviceHelper.GetClient();
HttpResponseMessage response = await client.GetAsync(dummyUrl);
return response;
}
catch (Exception)
{
// log.
throw;
}
}
}
単体テストプロジェクトで、モック用のヘルパークラスを作成しSendAsync
ます。ここでは、メソッドをオーバーライドするオプションを提供するFakeHttpResponseHandler
クラスです。上書きした後、セットアップにそれぞれの応答方法の必要性を呼びかけている作成し、そのための方法、となどととしてそうあるたびという場合と一致するように構成を返しますが。inheriting
DelegatingHandler
SendAsync
SendAsync
HTTP Request
SendAsync
Dictionary
key
Uri
value
HttpResponseMessage
HTTP Request
Uri
SendAsync
HttpResponseMessage
public class FakeHttpResponseHandler : DelegatingHandler
{
private readonly IDictionary<Uri, HttpResponseMessage> fakeServiceResponse;
private readonly JavaScriptSerializer javaScriptSerializer;
public FakeHttpResponseHandler()
{
fakeServiceResponse = new Dictionary<Uri, HttpResponseMessage>();
javaScriptSerializer = new JavaScriptSerializer();
}
/// <summary>
/// Used for adding fake httpResponseMessage for the httpClient operation.
/// </summary>
/// <typeparam name="TQueryStringParameter"> query string parameter </typeparam>
/// <param name="uri">Service end point URL.</param>
/// <param name="httpResponseMessage"> Response expected when the service called.</param>
public void AddFakeServiceResponse(Uri uri, HttpResponseMessage httpResponseMessage)
{
fakeServiceResponse.Remove(uri);
fakeServiceResponse.Add(uri, httpResponseMessage);
}
/// <summary>
/// Used for adding fake httpResponseMessage for the httpClient operation having query string parameter.
/// </summary>
/// <typeparam name="TQueryStringParameter"> query string parameter </typeparam>
/// <param name="uri">Service end point URL.</param>
/// <param name="httpResponseMessage"> Response expected when the service called.</param>
/// <param name="requestParameter">Query string parameter.</param>
public void AddFakeServiceResponse<TQueryStringParameter>(Uri uri, HttpResponseMessage httpResponseMessage, TQueryStringParameter requestParameter)
{
var serilizedQueryStringParameter = javaScriptSerializer.Serialize(requestParameter);
var actualUri = new Uri(string.Concat(uri, serilizedQueryStringParameter));
fakeServiceResponse.Remove(actualUri);
fakeServiceResponse.Add(actualUri, httpResponseMessage);
}
// all method in HttpClient call use SendAsync method internally so we are overriding that method here.
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if(fakeServiceResponse.ContainsKey(request.RequestUri))
{
return Task.FromResult(fakeServiceResponse[request.RequestUri]);
}
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.NotFound)
{
RequestMessage = request,
Content = new StringContent("Not matching fake found")
});
}
}
IServiceHelper
フレームワークなどをモックすることで、新しい実装を作成します。このFakeServiceHelper
クラスを使用してFakeHttpResponseHandler
クラスを挿入できるためHttpClient
、これによって作成されるたびに、実際の実装の代わりにclass
使用FakeHttpResponseHandler class
されます。
public class FakeServiceHelper : IServiceHelper
{
private readonly DelegatingHandler delegatingHandler;
public FakeServiceHelper(DelegatingHandler delegatingHandler)
{
this.delegatingHandler = delegatingHandler;
}
public HttpClient GetClient()
{
return new HttpClient(delegatingHandler);
}
}
テストでFakeHttpResponseHandler class
は、Uri
とを追加して構成しますHttpResponseMessage
。Uri
実際あるべきservice
エンドポイントUri
時になるようにoverridden SendAsync
する方法は、実際から呼び出されservice
、実装、それが一致するUri
にはDictionary
構成されてと応答HttpResponseMessage
。構成後FakeHttpResponseHandler object
、偽のIServiceHelper
実装に挿入します。次に、FakeServiceHelper class
を実際のサービスに挿入します。これにより、実際のサービスがoverride SendAsync
メソッドを使用するようになります。
[TestClass]
public class SampleServiceTest
{
private FakeHttpResponseHandler fakeHttpResponseHandler;
[TestInitialize]
public void Initialize()
{
fakeHttpResponseHandler = new FakeHttpResponseHandler();
}
[TestMethod]
public async Task GetMethodShouldReturnFakeResponse()
{
Uri uri = new Uri("http://www.dummyurl.com/api/controller/");
const int dummyParam = 123456;
const string expectdBody = "Expected Response";
var expectedHttpResponseMessage = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(expectdBody)
};
fakeHttpResponseHandler.AddFakeServiceResponse(uri, expectedHttpResponseMessage, dummyParam);
var fakeServiceHelper = new FakeServiceHelper(fakeHttpResponseHandler);
var sut = new SampleService(fakeServiceHelper);
var response = await sut.Get(dummyParam);
var responseBody = await response.Content.ReadAsStringAsync();
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
Assert.AreEqual(expectdBody, responseBody);
}
}
GitHubリンク:サンプル実装があります
HttpClient
インターフェースでを公開することが問題です。クライアントにHttpClient
具象クラスを使用することを強制しています。代わりに、の抽象化を公開する必要がありHttpClient
ます。