差分

ナビゲーションに移動 検索に移動

ASP.NET Web API/NUnitでユニットテストを行う

6,588 バイト追加, 2015年8月19日 (水) 02:36
編集の要約なし
[[ASP.NET Web APIのユニットテストをAPI]]の[[ユニットテスト]]を[[NUnit]]で行えると[[Xamarin Studio]]での開発が捗る。での[[開発]]が捗る。
==概要==
[[Xamarin.iOS]]や[[Xamarin.Android]]は[[ユーザーインターフェース]]と[[ビジネスロジック]]の分離が売り文句である。
環境依存のユーザーインターフェイスと、非依存のビジネスロジック。動作環境に依存する[[ユーザーインターフェース]]と、非依存しない[[ビジネスロジック]]という考えである。
しかし実際のところ猫も杓子もしかしならが、実際のところ猫も杓子も[[クラウドコンピューティング]]を叫ぶご時世であり、核となるを叫ぶご時世であり、また[[ビジネスロジックオンプレミス]]の[[社内システム]]も[[スタンドアローン]]で動くものは皆無である。[[サーバーiPhone]]上に実装される案件ばかりである。そうなると[[ビジネスロジックAndroid]]のアプリのような[[ASP.NET Web APIリッチクライアント]]を用いて記述しを用いる場合でも、核となる[[JSONビジネスロジック]][[XMLサーバー]]上に[[データWeb API]]のやりとりするのがもっとも手軽な実装方法であると思われる。として実装される案件ばかりである。
このような状況下ではクライアントもサーバーもそうなると[[Xamarin]]ホゲホゲを使った[[リッチクライアント]]に対向する[[ビジネスロジック]]は[[ASP.NET Web API]]を用いて記述し、[[JSON]]や[[XML]]で[[データ]]のやりとりするのがもっとも手軽な実装方法であると思われ、このような状況下では[[クライアント]]も[[サーバー]]も[[Xamarin Studio]]で一元的に開発を行えると桁違いに捗り、[[Xamarin Studio]]に統合されている[[NUnit]]が活躍する。が活躍すること間違い無しである。
==実装1==
1. 空のASP.NETプロジェクトを作る*NuGetからASPASP.NET Web APIを入れるAPIのユニットテストはAPIコントローラーの各メソッドをNUnitから直接呼び出す方法が手っ取り早い。
2. NUnitライブラリプロジェクトを作る*NuGetからASP.NET Web APIを入れる*ASP.NETプロジェクトを参照するしかしながら、[[Basic認証]]などのテストをしたい場合などもあるので、ここではインメモリサーバーを使用した方法を示す。
3===手順1===空のAPS. インメモリサーバーの準備をするNETプロジェクトを作成する。*なんでもいいのでNUnitプロジェクトからASPASP.NETプロジェクトのメソッドを呼び出す。*NUnitライブラリプロジェクトにインメモリサーバー関連のコードを記述するNET Web APIをNuGetから入れる
4動作検証用のAPIコントローラーを作る。: Controllers/HelloController. おわりcs<source lang="csharp">using System.Web.Http; namespace SampleWebApi.Controllers{ public class HelloController : ApiController { public string Get() { return "hello"; }  public string Post([FromBody] string name) { return "hello, " + name; } }}</source> ===手順2===NUnitライブラリプロジェクトを作る。*ASP.NET Web APIをNuGetから入れる*手順1のASP.NETプロジェクトを参照する**プロジェクトツリーの「参照」を右クリックし参照アセンブリの編集を選ぶ**Edit Referencesダイアログが開くので「Projects」タブを選ぶ**ソリューション内のプロジェクトの一覧が表示されるので手順1で作ったプロジェクトにチェックを入れる ===手順3===インメモリサーバーの準備をする。 なんでもいいのでNUnitライブラリプロジェクトからASP.NETプロジェクトのメソッドを呼び出す。これがとても重要。重要。なんでもいいがASP.NETプロジェクトにWebApiを初期化するコードを静的クラス・静的メソッドとして用意し、両方のプロジェクトで共有すると捗る。 WebApiを初期化するコードの例:App_Startup/WebApiConfig.cs<source lang="csharp">using System.Web.Http; namespace SampleWebApi{ public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Attribute routing. config.MapHttpAttributeRoutes();  // Convention-based routing. config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } }}</source> ASP.NETプロジェクトはGlobal.asax.csから呼び出す。<source lang="csharp">using System.Web.Mvc;using System.Web.Routing;using System.Web.Http; namespace SampleWebApi{ public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); GlobalConfiguration.Configure(WebApiConfig.Register); } }}</source>
NUnitプロジェクトはTestFixtureSetUp属性を付けたメソッドから呼び出す。
<source lang="csharp">
[TestFixtureSetUp]
public void Setup()
{
var config = new HttpConfiguration();
SampleWebApi.WebApiConfig.Register(config); // ←←←これ重要
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
}
</source>
 
===手順4===
NUnitライブラリプロジェクトにインメモリサーバー関連のコードを記述する。
<source lang="csharp">
using NUnit.Framework;
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Formatting;
using System.Web.Http;
 
namespace SampleWebApi.Tests
{
[TestFixture]
public class InMemoryTests
{
private const string UrlBase = "http://127.0.0.1:8080/";
 
private HttpServer _server;
 
[TestFixtureSetUp]
public void Setup()
{
var config = new HttpConfiguration();
// ASP.NETプロジェクトの何かしらのメソッドを呼び出す。
// 初期化コードを共通化しておくのが間違いないと思われる。
SampleWebApi.WebApiConfig.Register(config);
// エラーをいっぱいだす
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
 
// 重要
// ASP.NETプロジェクトの何かしらのメソッドを呼び出した後にインメモリサーバーのインスタンスを作ること
_server = new HttpServer(config);
}
public void Dispose()
{
if (_server != null)
{
_server.Dispose();
_server = null;
}
}
 
[Test]
public void Get()
{
using (var client = new HttpClient(_server))
{
var request = CreateRequest(
"api/Hello",
"application/json",
HttpMethod.Get);
 
using (var response = client.SendAsync(request).Result)
{
Assert.IsNotNull(response);
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
}
}
}
 
[Test]
public async void Post()
{
using (var client = new HttpClient(_server))
{
var request = CreateRequest(
"api/Hello",
"application/json",
HttpMethod.Post,
"monobook" ,
new JsonMediaTypeFormatter());
 
using (var response = client.SendAsync(request).Result)
{
Assert.IsNotNull(response);
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
}
}
}
 
private HttpRequestMessage CreateRequest(string url, string mthv, HttpMethod method)
{
var request = new HttpRequestMessage();
request.RequestUri = new Uri(UrlBase + url);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(mthv));
request.Method = method;
return request;
}
 
private HttpRequestMessage CreateRequest<T>(string url, string mthv, HttpMethod method, T content, MediaTypeFormatter formatter) where T : class
{
HttpRequestMessage request = CreateRequest(url, mthv, method);
request.Content = new ObjectContent<T>(content, formatter);
return request;
}
}
}
</source>
 
===おわり===
==関連項目==
匿名利用者

案内メニュー