MockHttpでHttpResponseをモック化!
最近C#ばっかりです。
なかなか型の制約とかHttpContextがHttpContextBaseを継承してなかったりとか色々としんどいです。
今回戸惑ったのがAPIのRequest⇔ResponseをMock化したかったのですが
NUGET辺りで探してたらいいのがありました。
これです。
github.com
今回はNUnitFrameWorkを使用しています。
using Newtonsoft.Json; using NUnit.Framework; using RichardSzalay.MockHttp; using System.IO; using System.Net; using System.Net.Http; using System.Threading.Tasks; using Exsample.Test.Common.Util; using Exsample.Net.Http; using Moq; using System.Web; using System; namespace Exsample.Module.Test { [TestFixture] public class GetStreamAsync : ClientContext { private string url; private Stream stream; private Error error; /// <summary> /// 成功時(status=OK)のMockResponseMessageをセット /// </summary> private void setSuccessContent() { mockHttpMessage.Expect($"{baseUrl}*") .Respond(() => { // Status 200時に実行されるCallBack。 // Task<HttpResponseMessage>型を返すようにする。 return Task.Factory.StartNew<HttpResponseMessage>(() => { var res = new HttpResponseMessage(); res.Content = new StreamContent(stream); return res; }); }); } /// <summary> /// 失敗時(status=NG)のMockResponseMessageをセット /// </summary> private void setFailContent() { error = new Error(); // シリアライズして文字列として第二引数に渡してます。 var content = JsonConvert.SerializeObject(error); mockHttpMessage.Expect($"{baseUrl}*") .Respond(HttpStatusCode.InternalServerError, "application/json", content); } /// <summary> /// MOCKのセットアップ。 /// </summary> /// <param name="isSuccess">成功テストか否か</param> public void mockSetup(bool isSuccess) { if (isSuccess) { // テスト用のダミーStreamを作成 stream = StreamCreator.Create(); url = "unittest/getasync"; setSuccessContent(); } else { url = "unittest/notfound"; setFailContent(); } } /// <summary> /// Status=OKのテスト /// </summary> /// <returns></returns> [Test] public async Task Success() { mockSetup(true); var result = await client.GetStreamAsync(url, null); Assert.AreEqual(stream, result); } /// <summary> /// Status=NGのテスト /// </summary> /// <returns></returns> [Test] public void Fail() { mockSetup(false); var exception = Assert.ThrowsAsync<ResponsException>(() => { return client.GetStreamAsync(url, null); }); Assert.AreEqual(HttpStatusCode.InternalServerError, exception.StatusCode); // クラス同時の比較は出来ないのでJSON化して比較 AssertObject(error, JsonConvert.DeserializeObject<Error>(exception.Message)); } } /// <summary> /// パラメーターのインスタンス化や共通のMock化を行う /// </summary> public class ClientContext : TestBase { protected TargetClient client; // テスト対象のメソッド Mock<HttpContextBase> mockContext; protected MockHttpMessageHandler mockHttpMessage; protected Guid userId; // 適当なURL protected string baseUrl = "http://exsample.com:8080/api/"; protected class Error { public string ErrorDiscription { get; set; } public string ErrorMessage { get; set; } public Error() { this.ErrorDiscription = "error_description"; this.ErrorMessage = "server_error"; } } [SetUp] public void Setup() { // MockのHttpContextBaseを作成 mockContext = FakeHttpContextBase.Create(); // HttpContextBaseをMock化をする。 // Sessionを上書きする var session = new Mock<HttpSessionStateBase>(); userId = Guid.NewGuid(); session.Setup(x => x["userId"]).Returns(userId.ToString()); mockContext.Setup(x => x.Session).Returns(session.Object); // 今回紹介するmockHttpMessageHandlerのインスタンスを作成。 mockHttpMessage = new MockHttpMessageHandler(); var httpClient = new HttpClient(mockHttpMessage); client = new TargetClient(mockContext.Object); client.HttpClient = httpClient; } } }
テスト対象メソッドはStatus=NGならばResponsExceptionをスロー。
メッセージ部分はJSON形式にて返却されます。
成功時は返却されたHttpResponseMessage.ContentをStreamにして返却しています。
APIのクライアント部分だし通信されると困るので、何かいいメソッドがないか見てたらいいのを見つけました。
今度もこれを使ってゴリゴリ書いていきたいと思います。