基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~

11,392 views
11,039 views

Published on

CLR/H 69回目勉強会でお話しさせて頂いた、ASP.NET MVC での TDD 基礎見直しです。あじゅらーもASP.NET MVC な人も是非ご一読あれ

0 Comments
10 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
11,392
On SlideShare
0
From Embeds
0
Number of Embeds
1,618
Actions
Shares
0
Downloads
41
Comments
0
Likes
10
Embeds 0
No embeds

No notes for slide

基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~

  1. 1. 基礎から見直す ASP.NET MVC の単体テスト自動化方法~ Windows Azure 関連もあるかも~ Microsft MVP for Windows Azure 割と普通 1
  2. 2. 自己紹介• 割と普通 ( @normalian ) – Windows Azure のコミュニティメンバ • Japan Windows Azure User Group http://r.jazug.jp/ – わんくま同盟 のコミュニティメンバ • http://www.wankuma.com/ – Microsoft MVP for Windows Azure 2010~ 2
  3. 3. 本セッションの目的とゴール• 目的 – C#/VB.NET で単体テスト自動化するため、どのよ うにテストコードを記述すれば良いかを認知 – 単体テスト自動化を支援するツール、ライブラリ群を 認知• ゴール – C#/VB.NET で、単体テストの自動化が可能なテ ストコードを効率的に記述することができる 3
  4. 4. アジェンダ 何故 単体テスト自動化 が必要? 単体テスト自動化 のコツ 単体テストを効率化するツール群 まとめ 参考
  5. 5. 何で単体テスト自動化が必要?• 良く言われるのは以下のメリット – 単体テストの工数を削減できる – コードの保守・再利用性が向上する – コードが綺麗になる 5
  6. 6. 単体テストの工数を削減できる仕様変更が増える程、単体 テスト工数は増大 6
  7. 7. コードの保守・再利用性が向上する• 変更に伴うデグレを瞬時に検知できる – リファクタリングや保守が容易 – 単体テストコードの動作検証がいつでも可能• 外部仕様が容易に理解できる – メソッドの外部仕様がテストコードに記載 – ドキュメント・コードの二重化を防止 7
  8. 8. コードが綺麗になる• ソースコードのテスタビリティが向上する – 単体テストの自動化を意識したインターフェースの定 義を強制 – テストコードをマニュアルとして利用可能 – コーディング力が向上• 若手、新人の教育向けに適用できる 8
  9. 9. アジェンダ 何故 単体テスト自動化 が必要? 単体テスト自動化 のコツ 単体テストを効率化するツール群 まとめ 参考
  10. 10. 単体テストの対象を明確化する• データの入出力ポイントに対して単 体テストを実施する モデルのテストHTML/ Java 画面 コント モデル CSS Script モデル ローラJavaScript で記 JavaScript から コントローラの述したロジック C# へのマッピ テストのテスト ング JavaScript C# 10
  11. 11. 単体テスト自動化が容易なインター フェースを定義する 1/3• 従来の ASP.NET Web Forms では、単体テ ストの自動化がきわめて困難 メインコード テストコード
  12. 12. 単体テスト自動化が容易なインター フェースを定義する 2/3• ASP.NET MVC で単体テストの自動化が容易に メインコード テストコード
  13. 13. 単体テスト自動化が容易なインター フェースを定義する 3/3• Testing Framework や NUnit 等で自動テ スト可能な外部インターフェース設計とする ViewReult コント • ViewBag ローラ • Model Web API の 応答 XXXXResult (その他の応答) 13
  14. 14. 変数名の命名規則に留意する 1/2• テストメソッド名、変数名からチェック対象を理解 できるように命名する良い例 [TestMethod] public void Indexがリストを返す() { List<string> expect = new List<string>(){ "a", "b", "c" }; List<string> actual = null; HomeController controller = new HomeController(); actual = (controller.Index() as ViewResult).Model; Assert.Equals( expect, actual ); } 14
  15. 15. 変数名の命名規則に留意する 2/2• 「悪い例」では、テストメソッド名、変数名から チェック対象が理解できない悪い例 [TestMethod] public void Index () { HomeController controller = new HomeController(); var actual = (controller.Index() as ViewResult).Model; Assert.Equals(new List<string>(){ "a", "b", "c" }, actual ); } 15
  16. 16. 1メソッド・1アサートを心がける 1/2• テスト対象を明確化するため、1メソッド・1アサートを 心がける• if 文, for 文, while 文に Assert はダメ、絶対良い例 string expect = XXXXXX; string actual = null; (中間ロジック) Assert.Eqauls( expect, actual ); 16
  17. 17. 1メソッド・1アサートを心がける 2/2• 「悪い例」では、チェックする場所が散って何をチェックして いるか分からない悪い例 string expect = XXXXXX; string actual = null; (中間ロジック) if(flag == true) { Assert.Eqauls( expect, actual ); }else{ Assert.Fail(“ここは通らないはず”); } 17
  18. 18. モックを効率的に作成する 1/2• Moq.dll 等を利用して HttpContextBase, IPrincipal, IIdentity 等のモック作成が難しい クラスを作成する [TestMethod()] public void IndexTest01() { • Moq.dll を利用してもス string expect = typeof(RedirectToRouteResult).FullName; string actual; BuyHistoryController target = new BuyHistoryController(new TestOrderRepository()); テップ数が多い //モックの作成 var mockHttpContextBase = new Mock<HttpContextBase>(); • Moq.dll を利用しないと var mockIdentity = new Mock<IIdentity>(); var mockPrincipal = new Mock<IPrincipal>(); 数倍のコード行数になる //ユーザ情報の設定&httpContextオブジェクトの作成 mockIdentity.Setup(identity => identity.IsAuthenticated).Returns(true); mockIdentity.Setup(identity => identity.Name).Returns("someUser"); mockPrincipal.Setup(principal => principal.Identity).Returns(mockIdentity.Object); mockHttpContextBase.Setup(httpContextBase => httpContextBase.User) .Returns(mockPrincipal.Object); ControllerContext context = new ControllerContext(mockHttpContextBase.Object, new RouteData(), target); target.ControllerContext = context; actual = target.Index().GetType().FullName; Assert.AreEqual(expect, actual); } 18
  19. 19. モックを効率的に作成する 2/2• モック作成は行数が伸びるので共通化する[TestMethod()]public void IndexTest01(){ string expected= typeof(RedirectToRouteResult).FullName; string actual; BuyHistoryController target = モック作成を共通化 new BuyHistoryController(new TestOrderRepository()); ControllerContext context = new ControllerContext( Utils.CreateControllerContext(true, "someuser") , new RouteData(), target); target.ControllerContext = context; actual = target.Index().GetType().FullName; Assert.AreEqual(expect, actual);} 19
  20. 20. 名前空間、クラス名の命名規則に留意する• テスト対象のプロジェクト、クラスが分かりやすいよう に命名規則を規定する – プロジェクト名:MyMVC → MyMVC.Test – クラス名: MyClass → MyClassTest – メソッド名: MyMethod → MyMethodTest• 命名規約に従うことで、 TestDriven.NET を利 用した、メインコード/テストコードの切り替えが可能 – http://www.testdriven.net/quickstart.aspx 20
  21. 21. アジェンダ 何故 単体テスト自動化 が必要? 単体テスト自動化 のコツ 単体テストを効率化するツール群 まとめ 参考
  22. 22. ツールを利用したテスト効率化したい• 紹介したツール・ライブラリを利用 してテストを自動化するHTML/ Java 画面 コント モデル CSS Script モデル ローラ JavaScript C# 22
  23. 23. ツールを利用したテスト効率化(β)• 紹介したツール・ライブラリを利用 してテストを自動化するHTML/ View View コント モデル CSS Model Model ローラ knocko Entity knock AutoM ut.map Frame out.js apper ping.js work JavaScript C# 23
  24. 24. ツールを利用したテスト効率化(β)• 紹介したツール・ライブラリを利用 してテストを自動化するHTML/ View View コント モデル QUnit-tap CSS Model Model Testing ローラで単体テス knocko Framework Entity ト自動化 ut.map 単体テスト自動化 knock AutoM Frame out.js appernode.exe ping.js MSTest.exe work JavaScript C# 24
  25. 25. 紹介するツール・ライブラリ群• 今回は以下のライブラリ・ツールを紹介 – knockout.js – knockout.mapping.js – AutoMapper – Qunit-tap
  26. 26. knockout.js• DOM 要素と JSON オブジェクトのマッピング機能 var viewModel = { left: ko.observable( 30 ), right: ko.observable( 40 ) onblur 等のイベントが発生した }; タイミングで、ViewModel と viewModel.answer = DOM要素で値を同期 ko.dependentObservable(function () { return parseInt(this.left()) + parseInt(this.right()); }, viewModel); ko.applyBindings(viewModel); <input type=“text” data-bind=“value: left” /> + <input type=“text” data-bind=“value: right” /> = <span data- bind="text: answer"></span> 26
  27. 27. Knockout.mapping.js 1/2• C#/VB.NET の ViewModel と JSON オブジェクト をマッピング { name: “若人”, age: 20} 等のJSONに置換される処理 <script type="text/javascript"> //JSONオブジェクトから、ViewModel を作成 var initialData = @Html.Raw(Json.Encode(Model)); var viewModel = ko.mapping.fromJS(initialData); //DOM要素を読み込み後、ViewModel を Binding $( function(){ ko.applyBindings(viewModel); }); </script> DOM 要素 と viewModel イ ンスタンスとを双方向バインド 27
  28. 28. Knockout.mapping.js 2/2• C#/VB.NET の ViewModel と JSON オブジェクト をマッピング $.ajax({ type:“POST”, dataType: "json", contentType: "application/json", data : ko.mapping.toJSON(viewModel), url: "@Url.Content("~/api/Values/")", success : function(res){ alert(JSON.stringify(res)); } }); public class ValuesController : ApiController{ public string Post(ViewModel viewModel){ return "server recieved answer = " + viewModel.answer; } 28
  29. 29. AutoMapper• Model – ViewModel といったモデル間のマッピ ングを実施する• 複数モデルからの集約化等、細かな制御が可能 Model ViewModel 項目1 項目2
  30. 30. AutoMapper• 「XXX.ID = YYY.ID」の羅列を防止できる• マッピングが存在しない場合は一括でチェック可能 Product product = ProductRepository.GetById(id); Mapping.AutoMapperBootstrapper.Configure(); Mapper.CreateMap<Product, ProductViewModel>(); Mapper.Map<Product, ProductViewModel>(product); var productViewModel = Mapper.Map<Product, ProductViewModel>(product);
  31. 31. QUnit-tap の利用• node.exe から実行可能な QUnit – node.exe → Node.js の Windows 実装 – QUnit → ブラウザ上で JavaScript を単体テスト• knockout.js の ViewModel が対象? require(../test_helper.js); QUnit.test(my calc test, function() { var expect = 3; var actual = calc( 1, 2 ); assert.equal(expect, actual); }); QUnit.start();
  32. 32. アジェンダ 何故 単体テスト自動化 が必要? 単体テスト自動化 のコツ 単体テストを効率化するツール群 まとめ 参考
  33. 33. まとめ• ASP.NET MVC は単体テストの自動化に向 いている• 単体テストの自動化を実施するためにはコツ がある• 単体テストの自動化を支援するツールは多々 存在する
  34. 34. View と コントローラの構成 (β)HTML/CSS ViewM View knockout.map Contr Model knockout.js Model ping.js odel oller Entity FrameworkHTML/CSS ViewM View knockout.map knockout.js Model ping.js odel ModelHTML/CSS View ViewM Entity knockout.map knockout.js Model ping.js odel Framework 1対N N対M 1対1 対応 対応 対応 対応関係 C# JavaScript
  35. 35. アジェンダ 何故 単体テスト自動化 が必要? 単体テスト自動化 のコツ 単体テストを効率化するツール群 まとめ 参考
  36. 36. 参考 1/2• InfoQ – ASP.NET MVC のテスト方法 – http://www.infoq.com/jp/news/2012/03/aspnet- unit-test• MSDN Library – ASP.NET MVC アプリケーションの単体テスト – http://msdn.microsoft.com/ja- jp/library/ff936235.aspx• ASP.NET MVC3 における単体テストの基礎 – http://codezine.jp/article/detail/6493• wa りと na はてな日記 - Moq.dll on ASP.NET MVC その2 – http://d.hatena.ne.jp/waritohutsu/20090909/
  37. 37. 参考 2/2• knockout.js Documentation > mapping – http://knockoutjs.com/documentation/plugins- mapping.html• knockout.js Documentation > The “template” binding – http://knockoutjs.com/documentation/template- binding.html• knockout.js の注意すべき点 – http://d.hatena.ne.jp/shiba-yan/20120130/• miso_soup3 - AutoMapper+ViewModel In MVC その2 – http://d.hatena.ne.jp/miso_soup3/20120408/
  38. 38. 余談!
  39. 39. というか続編!
  40. 40. クラウド上で単体テスト自動化• Trac Lightning on Windows Azure – https://github.com/normalian/WATracLightning
  41. 41. テスト自動化もクラウドへ…単体テスト自動化(手動キック) 単体テストの自動化 (自動キック) 全てクラウドへ・・・
  42. 42. 自はこ 動ての テし スな トく 坂遠 をい よ ・ ・ ・未 ばのよオ かぼうレ りりやは だはく かじ完 らめ なた

×