これまでのテストをするためにUnitTestを使っていますが、所謂↓を使っています。
Silverlight Unit Test Framework
http://code.msdn.microsoft.com/silverlightut/
ロジックだけであれば、NUnitとかMicrosoftが提供するTest Frameworkを使えばいいのですが、画面が絡むと途端に面倒になるので。
さて、この「Silverlight Unit Test Framework」ですが、ダミーでボタンをぽちぽち押してくれるようなタイプではありません。先のエントリを見ると分ると思いますが、他のUnitTestと同様にメソッドを羅列していきます。
なので、画面のフォーカス/アウトフォーカスみたいなイベントを取れません。
まあ、本当はそれで動かないと駄目なんですけど、試してみると画面の動きが違ったりして(特に間違ったDataContextの指定の仕方とかすると)なにかとややこしいのですが。
このあたりのイベント絡みをやるためには、別途javascriptとかを組まないと駄目そうですね。
画面のほうは、至ってシンプルです。
ただし、テスト結果がブラウザ上でしか確認できないので、自動化には向いていないそうです(というブログがありました)。
さて、使い始めは何事も躓きやすいのでポイントだけ示しておきます。
■プロジェクトを3分割する
UnitTestをする場合、プロジェクトを3つに分けます。
・テスト対象のプロジェクト(SampleTextBinding)
・テストプロジェクト(SampleTextBinding.Test)
・テスト実行のプロジェクト(SampleTextBinding.Test.Web)
画面やロジックしてあるのは SampleTextBinding のプロジェクトです。
出来る限りここには手を加えないようにします。
テストプロジェクトは TestCase を書いていきます。
テスト実行のプロジェクトはWebのプロジェクトです。テストプロジェクトと一緒にしてもいい気もしますが、なんかうまくいかないので、別々にしました。
■テストプロジェクトに3つの参照を追加する
最初にテストプロジェクトに手を入れます。
参照設定に以下のアセンブリを追加します。
・Microsoft.Silverlight.Testing
・Microsoft.Silverlight.Testing.Framework
・Microsoft.VisualStudio.QualityTools.UnitTesting.Silverlight
■テストケースを作る
テストケースのひな形は、マイテンプレートから「Silverlight Test Case」で追加してもよいですし、
次のひな形を使っても構いません。
using System; using System.Collections.Generic; using Microsoft.VisualStudio.TestTools.UnitTesting; using SampleTextBinding; using Microsoft.Silverlight.Testing; using System.ComponentModel; namespace SampleTextBinding.Test { [TestClass] public class TestCase001 : SilverlightTest { private Page _page; [TestInitialize] public void SetUp() { _page = new Page(); } [TestMethod] public void TestMethod001() { // ここに記述 } } }
ひとまとまりのテストケースには「TestClass」の属性を付けます。
SilverlightTest クラスは普通は継承しなくてもよいのですが、非同期のテストの場合はこれを継承します。
私の場合は、必ずページを開くことになるので、初期化時のメソッドSetUpに「TestInitialize」の属性をつけて、初回に実行するようにします。
メソッドを書くときは「TestMethod」をつければOK。
最初は練習用に
public void TestMethod001() { Assert.AreEqual( 1,1 ); }
のように必ず通るテストを付けておけばOKです。
そうそう、忘れていけないのは、App.xml.cs の修正です。
private void Application_Startup(object sender, StartupEventArgs e) { // this.RootVisual = new Page(); this.RootVisual = (UIElement)UnitTestSystem.CreateTestPage(this); }
こんな風にテストページを RootVisual に設定してください。
このとき Silverlight 2 の場合は UIElement へのキャストが必要です。
■テストを動作させるプロジェクトを設定する
SampleTextBinding.Test.Web プロジェクトのことですね。このプロジェクトにテストを動作させるページを追加します。
まず、プロジェクトを右クリックして「プロパティ」を選択します。
「Silverlightアプリケーション」のタブを開いて、追加ボタンを押します。
対象のアプリケーションを選択できるので「SampleTextBinding.Test」のほうを選択します。
すると、SampleTextBinding.TestTestPage.html のようなページができるのでスタートアップページに設定します。そうそう、SampleTextBinding.Test.Web プロジェクトをスタートアップに設定してください。
さて、これで準備完了。どんどんテストを行ってください。
画面のプロジェクトを「なるべく触らない」と書きましたが、実はボタンイベントの場合は触らないと駄目です。
実はボタンイベントは private で設定されてます。
private void BtnSave_Click(object sender, RoutedEventArgs e) { ... }
なので、これを外側から呼び出すことはできません。public に変えてもいいのですが、本番のクラスのアクセス権を変更してしまうのは問題があります。
というわけで仕方がないので internal を使ったメソッドを作ります。
/// 以下、テスト用 internal void TestBtnSaveClick() { BtnSave_Click(this, new RoutedEventArgs()); }
internal は同じアセンブリから呼べる、という protected と public の間みたいな制限を付けられます。
ここで裏ワザ(かな?)があり、AssemblyInfo.cs に次の記述を書くと別アセンブリのクラスから呼び出せます。
[assembly: InternalsVisibleTo("SampleTextBinding.Test")]
こうすることで、TestMethod のほうから、無事 TestBtnSaveClick を呼べるようになり、ボタンクリックのイベントを発生させられるのです。
Silverlight Unit Test Framework のページには、この他に非同期呼び出しのテストの解説も載っているので参考にしてください。
余談
ボタンのイベントなんですが、Java の UnitTest の潮流から言えば、この internal の方法が正しいのですが、テスト用とはいえ、internal メソッドを入れてしまうのが気に入りません。
できることなら、Windows アプリの SendMessage や SendKey みたいなのでエミュレートしたいですねぇ。