2008-02-07
λ [.NET] ASP.NET サーバーコントロール 単体テスト with TypeMock + MSTest
HTMLレンダリングのテストは以前からできていたのだが、 Redirect によるページ遷移の部分をどうテストするのかが課題だった。 Redirect の呼び出しを TypeMock を利用することによってテスト可能にする。
テストフレームワークは VisualStudio 2008 Professional で利用できるようになったこともあるので MSTest
(当初 Native Mock 使ってみようかと思ったが Reflective Mock で記述した。 なので TypeMock 無料版でもいけるはず。現在は入れたばかりなので Enterprise 評価モード)
テストしたいサーバーコントロール。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace ServerControl1
{
[ToolboxData("<{0}:ServerControl1 runat=\"server\" />h")]
public class ServerControl1 : WebControl
{
protected override void OnPreRender(EventArgs e)
{
HttpContext.Current.Response.Redirect(ResolveUrl("~/tako.aspx"), true);
}
}
}
テストコード。テストコードの最初の枠組みは VisualStudio 2008 で、上記の OnPreRender に対して「単体テストの作成」を行う。 これにより protected メソッドに対するアクセサ(ServerControl1_Accessor)をVS2008が自動的に生成してくれる。
using ServerControl1;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using System.Text;
using System.Web;
using System.Web.Hosting;
using TypeMock;
namespace TestProject1
{
/// <summary>
///ServerControl1Test のテスト クラスです。すべての
///ServerControl1Test 単体テストをここに含めます
///</summary>
[TestClass()]
public class ServerControl1Test
{
HttpContext savedContext;
#region 追加のテスト属性
//各テストを実行する前にコードを実行するには、TestInitialize を使用
[TestInitialize()]
public void MyTestInitialize()
{
MockManager.Init();
savedContext = HttpContext.Current; // 一応保存しとく
}
// 各テストを実行した後にコードを実行するには、TestCleanup を使用
[TestCleanup()]
public void MyTestCleanup()
{
MockManager.Verify();
HttpContext.Current = savedContext;
}
#endregion
/// <summary>
///OnPreRender のテスト
///</summary>
[TestMethod()]
[DeploymentItem("ServerControl1.dll")]
public void OnPreRenderTest()
{
Mock targetMock = MockManager.MockAll(typeof(ServerControl1.ServerControl1), Constructor.NotMocked);
targetMock.ExpectAndReturn("ResolveUrl", "ResolveUrl succeeded").Args("~/tako.aspx"); // Pageの中にコントロールを配置していないので、そのままでは ResolveUrl が失敗する。"ResolveUrl succeeded" で差し替える。
Mock responseMock = MockManager.MockAll(typeof(HttpResponse), Constructor.NotMocked);
responseMock.ExpectCall("Redirect").Args("ResolveUrl succeeded", true); // Response.Redirect の第二引数なしでの呼び出しは Verify に失敗する。第一引数は上記 ResolveUrl が返した仮の値のはず
{
string appVirtualDir = "/Site1"; // Webアプリケーション 仮想ディレクトリ
string appPhysicalDir = @"C:\temp\ServerControl1\Site1"; // Webアプリケーション 物理ディレクトリ
string page = "Default.aspx"; // ページファイル
string queryString = "a=1&b=2";
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
HttpWorkerRequest wr =
new SimpleWorkerRequest(appVirtualDir, appPhysicalDir, page, queryString, sw);
HttpContext.Current = new HttpContext(wr);
ServerControl1_Accessor target = new ServerControl1_Accessor();
EventArgs e = new EventArgs();
target.OnPreRender(e);
}
// レンダリング結果が必要なら sb の中身を調べる
}
}
}
}
λ Expression Media Encoder
Window Media Encoder で画面操作のキャプチャをした後に、キャプションをつけたいと思ったのだが、 現在のところ日本語キャプションはつけられない、とあった。使えん… CAMTASIA Studio とどっちにしようか悩み中。
Expression Design との合わせ技だと Expression Media Encoder はお買い得な気もするし。 とりあえず本当にキャプションつけたくなるまでしばらく待つか。
λ LiveMeeting
次期MCP資格についての LiveMeeting に参加した。参加したっても基本的にはプレゼン聞いてるだけだけど。
早口の英語聞き取りはまだまだ苦しい。資料が画面に出ている分には大筋で間違った理解はしてないとは思うけど、 Q&Aのところは聞き取れない。
λ Mocking .NET 3.5
TypeMock の最新版では、LINQ を利用するところを Mocking できる。 こういうときは Natural Mocks の威力発揮だな。 テスト可能にするために実コードに対する修正をしたり、アクロバティックなコードを書くのは、 品質向上に対して良くないと思われるので TypeMock を利用することはかなり検討する価値がある。
サンプルコードそのままコピペ(コメントだけ日本語化)
// C#
/// サンプルデータ。実際には利用しない
private List<Customer> m_CustomerList = new List<Customer> {
new Customer{ Id = 1, Name="Dave", City="Sarasota" },
new Customer{ Id = 2, Name="John", City="Tampa" },
new Customer{ Id = 3, Name="Abe", City="Miami" }
};
/// <summary>
/// LINQ 呼び出しの モックサンプル
/// </summary>
[TestMethod]
[VerifyMocks]
public void MockComplexQuery()
{
// 返り値として利用する にせオブジェクト fake
var fake = new[] {new {Name="mock",City="LA"},
new {Name="mock2",City="NY"}};
// ここから モック の指定
using (RecordExpectations r = new RecordExpectations())
{
// LINQ呼び出しをモックする指示
var answer =
from c in m_CustomerList
where c.City == "Sarasota"
select new { c.Name, c.City };
// 上記呼び出しに対する 返り値は fake を利用する
r.Return(fake);
}
// 実際に実行されるテストコード
var actual =
from c in m_CustomerList
where c.City == "Sarasota"
select new { c.Name, c.City };
// fake が返ってきたかどうか確認
Assert.AreEqual(2, actual.Count());
Assert.IsTrue(actual.Contains(new { Name = "mock", City = "LA" }));
Assert.IsTrue(actual.Contains(new { Name = "mock2", City = "NY" }));
}
でも現時点で LINQ って使いどころがいまいちわからん。 抽象化して、[操作]に対して[データの入れ物]を可換にしたいんだろうとは思うんだけど、 あんまり抽象化すると最適化できないわけで。
LINQ to (SQLServerでない何か) の場合に、SQL Server みたいにインデックス付与を後から差し込んでチューニングできる、 とかになれば嬉しそうだ。WCF と同様に config の書き換えでチューニング、 動作した結果は変わらないけどスピードが変わるみたいな。
λ FlySSLのSSLサーバ証明書を買ってみた
$7.99/year メールアドレス認証だけ。
証明書の Subject がどうなってるかは書いてないのでわからんけど、実在証明してないんだからそれなりなんだろう。 警告出ないようにするだけだったらこれでもいいな。
using plugin: amazon calendar2 category html_anchor makelirs makerss recent_comment3 recent_trackback3 squeeze tb-send tb-show recent_list
Copyright(C) 2003-2007 by KAMIYA Satosi (上美谷 智史) All rights reserved.