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しか扱えないようになっているのでこの辺ももう少し改良が必要かも。