taediumの日記

2010-09-19

[][] SilverlightのテストサポートについてMicrosoft Connectに要望を提出

2週間ほど前にフォーラムで、Silverlight4の単体テストについてというタイトルのディスカッションを投稿しました。このスレッドで出た意見をまとめて、今度は、Microsoft Connectにフィードバックを投稿しました。

簡単にでまとめると、Visual StudioSilverlightのテストを正式にサポートしてドキュメントにもテストのガイドラインを示してほしい!という内容です。


賛同していただける方は、ぜひvoteお願いします。コメントもできるようなので、補足などしていただけるとうれしいです。

2010-09-09

[][] WCF RIA Servicesでモック

WCF RIA ServicesのDomainContextをモックする方法を見て。

自分はちょっと汎用的なDomainClientを作ってみました。DomainClientに期待値を返すFuncを登録して使う方式です。

DomainClientのサブクラス(モック)
public class MockDomainClient : DomainClient
{
    public Func<IAsyncResult, QueryCompletedResult> EndQueryFunc{ get; set; }

    public Func<IAsyncResult, SubmitCompletedResult> EndSubmitFunc { get; set; }

    public Func<IAsyncResult, InvokeCompletedResult> EndInvokeFunc { get; set; }

    protected override IAsyncResult BeginQueryCore(EntityQuery query, AsyncCallback callback, object userState)
    {
        var asyncResult = new MockAsyncResult(userState);
        callback(asyncResult);
        return asyncResult;
    }

    protected override QueryCompletedResult EndQueryCore(IAsyncResult asyncResult)
    {
        return EndQueryFunc(asyncResult);
    }

    protected override SubmitCompletedResult EndSubmitCore(IAsyncResult asyncResult)
    {
        return EndSubmitFunc(asyncResult);
    }

    protected override InvokeCompletedResult EndInvokeCore(IAsyncResult asyncResult)
    {
        return EndInvokeFunc(asyncResult);
    }
}
適当なIAsyncResultの実装
public class MockAsyncResult : IAsyncResult
{
    private readonly object _asyncState;

    public MockAsyncResult(object asyncState)
    {
        this._asyncState = asyncState;
    }

    public bool IsCompleted
    {
        get
        {
            return true;
        }
    }

    public WaitHandle AsyncWaitHandle
    {
        get
        {
            return null;
        }
    }

    public object AsyncState
    {
        get
        {
            return _asyncState;
        }
    }

    public bool CompletedSynchronously
    {
        get
        {
            return true;
        }
    }
}
Silverlight Unit Test Frameworkを使ったテストコード
[TestClass]
public class Tests : SilverlightTest
{
    [TestMethod]
    [Asynchronous]
    public void TestMethod1()
    {
        var book = new BookModel
                   {
                       BookId = 1
                   };
        var entities = new List<Entity>
                       {
                           book
                       };
        var client = new MockDomainClient
                     {
                         EndQueryFunc = _ =>
                                        new QueryCompletedResult(entities, Enumerable.Empty<Entity>(), 1, new List<ValidationResult>())
                     };
        var viewModel = new BooksViewModel(new BookCircleContext(client));
        viewModel.SearchText = "A";
        viewModel.Search();
        EnqueueConditional(() => viewModel.CurrentOperation.IsComplete);
        EnqueueCallback(
            () => Assert.AreSame(book, viewModel.SelectedBook));
        EnqueueTestComplete();
    }
}

この方法のメリットはどのテストでもMockDomainClientを使うことができます。

DomainClientのプロパティにQueryCompletedResultを返すFuncを返すようにしていますが、期待されるエンティティだけ登録するとかもう少しAPIを使いやすくしたほうがいいかもしれません。それと、1度のテストで1つのQueryしか扱えないようになっているのでこの辺ももう少し改良が必要かも。

2010-09-04

[][] Silverlight単体テストの問題点について

ディスカッションという種別でフォーラムに投稿してみました。

Silverlight、テストがもう少ししやすければ楽なのになーとよく思います。興味のある方、意見ください。よろしくお願いします。

有効な解決策が出てこない場合は、MicrosoftConnectに投げてみたいと思います。

TechEdで聞いてきたんですけど、重複は気にしなくていいからMicrosoftConnectどんどん使いましょうというお話がありました。実践してみます。

2010-07-14

[][] Expression Blend 4を入れてみた

Expression Blend 4ってMVVMをサポートしていると謳っているんですね。

New ProjectでSilverlight Databound Applicationというテンプレートを選ぶと、ViewとViewModelを使った簡単なサンプルが含まれるプロジェクトが生成されました。そして、ViewからViewModelを呼び出すコードはトリガー(ビヘイビア)を使っていました。

<Button Content="Update Value" Height="41" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0,125,0,0">
	<i:Interaction.Triggers>
		<i:EventTrigger EventName="Click">
			<ic:CallMethodAction MethodName="ViewModelMethod" TargetObject="{Binding}"/>
		</i:EventTrigger>
	</i:Interaction.Triggers>
</Button>

ドキュメントにも、MVVMで使えるビヘイビアという位置づけで説明されていました。

New behaviors for use with applications that use the Model-View-ViewModel pattern include the following: CallMethodAction, InvokeCommandAction, and DataStateBehavior. You can use these behaviors to invoke behavior on your ViewModels, or to respond to changes to their properties.

http://msdn.microsoft.com/en-us/library/cc294722%28Expression.40%29.aspx


先日見つけたPrism4.0 Drop3のサンプルもフォルダ構成を見るにExpression Blendを使って作られたんだと思います。ビヘイビアは、Silverlight標準の機能になっていてほしいなぁ。

2010-07-11

[][] Prism 4.0 Drop 3

Silverlight4に対応したというPrism2.2をちょっとみていたのですが、よくよく見ると次のバージョンのベータ版のようなものがPrism 4.0 Drop 3としてリリースされていました(Dropって感覚的にアルファとかベータみたいなものだと思うんですけど、バージョンを表すものとしては初めて聞いた気がします)。

http://compositewpf.codeplex.com/releases/view/48172

いまのところ、Unityの代わりにMEFを使えるようになったのが大きな新機能のようです。

QuickStartsには、Prism使わない版のMVVMのサンプルとモジュール(XAP)をオンデマンドでロードするサンプル(MEFとUnity版それぞれ)が含まれています。

MVVMのサンプルは当然ICommand使っているんだろうなと思っていたら使っていなかったです。Blendに入っているアセンブリのSystem.Windows.Interactivityを使ってこう書いていました。

        <Button Grid.Row="2" Grid.Column="2" Content="Reset" Height="23" HorizontalAlignment="Right"  x:Name="button1" Width="75">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <ei:CallMethodAction TargetObject="{Binding}" MethodName="Reset"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>

標準のICommandを使わないというのはこっちのほうが簡単っていう判断なんでしょうかね。


モジュールをオンデマンドでロードする機能はPrism2.2にすでに入っていましたが、依存関係を解決したりロードするオプションがいくつかあったりなかなか便利そうです。

[][] PrismのEventAggregatorがスレッドセーフじゃない

Prismの魅力的な機能として、EventAggregator(http://msdn.microsoft.com/en-us/library/ff647984.aspx)というものがあるのですが、コードを見てみたらスレッドセーフじゃなかったです。

実装は簡単に差し替えられるので自分でスレッドセーフ版をつくるのがいいかもしれないですね。

Stack Overflowで確認している人もいました。

http://stackoverflow.com/questions/2834035/eventaggregator-is-it-thread-safe