Print Page | Close Window

Silverlight Unit Test Example

Printed From: IdeaBlade
Category: DevForce
Forum Name: DevForce 2009
Forum Discription: For .NET 3.5
URL: http://www.ideablade.com/forum/forum_posts.asp?TID=1343
Printed Date: 22-Sep-2025 at 4:22am


Topic: Silverlight Unit Test Example
Posted By: skingaby
Subject: Silverlight Unit Test Example
Date Posted: 23-Jun-2009 at 11:07am
In an effort to test my Client Model, I created a Silverlight UnitTest project ( http://code.msdn.microsoft.com/silverlightut - http://code.msdn.microsoft.com/silverlightut ). A Google search for "silverlight unit test asynchronous" helped a lot too.

Here are the steps I used:
1) I used the SilverlightUT template to create a new project.
2) I added a reference to the IdeaBlade.x.SL assemblies, the Ideablade sample Prism Explorer Infrastructure project (for the TypeHelper class) and to my Client Model project.
3) I went to the properties of my ShellWeb project (the host for the Silverlight apps) and went to the Silverlight Applications tab where I added the ClientModel.Test project and its new test container page.
4) I added a unit test to the Test.cs file that the template created for me in step 1.
5) I spent a ridiculous amount of time debugging said unit test.
6) I finally did a little happy dance and some Matchitecture as a reward for getting it done.

Here is a working sample of the test I ran to demonstrate connectivity from client to server:

[TestClass]

public class Test : SilverlightTest
{
    private DomainModel.DomainModelEntityManager _em = new DomainModel.DomainModelEntityManager();

    [TestMethod]
    [Asynchronous]
    public void LoadAllDeals()
    {
        EnqueueCallback(() => _em.LoginAsync(null, args2 => LoginCallback(args2, null), null));
    }

    private void LoginCallback(LoginEventArgs args2, Action callback)
    {
        if (args2.Error != null)
            throw args2.Error;
        Assert.IsTrue(_em.IsLoggedIn);
        Assert.IsTrue(_em.IsConnected);
        _em.DefaultQueryStrategy = QueryStrategy.Normal;
        EnqueueCallback(() => _em.ExecuteQueryAsync(_em.Deals, args => QueryCallback(args, null), null));
    }

    private void QueryCallback(EntityFetchedEventArgs args, Action<IEnumerable> callback)
    {
        IList dls = TypeHelper.CreateObservableCollection(args.Result);
        Assert.IsNotNull(dls);
        Assert.IsTrue(dls.Count > 0);
        EnqueueTestComplete();
    }
}


Notice:
a) The Test class inherits from SilverlightTest
b) The test method LoadAllDeals has the [Asynchronous] attribute
c) Any call that needs a callback is done as a lambda expression inside the EnqueueCallback() method of the base SilverlightTest class
d) It was not necessary to Enqueue the Assertions
e) The last callback in the chain completes the chain by calling the EnqueueTestComplete() method.



Replies:
Posted By: skingaby
Date Posted: 29-Jul-2009 at 12:24pm
Here is an example of a more advanced test. This one uses the Ideablade provided AsyncParallelTask to run a bunch of queries to preload the Cache. It also uses the AsyncSerialTask to create the chain of tasks.   Whereas the above example shows the LoginAsync in one method and then the LoginCallback, which in turn calls the ExecuteQueryAsync which calls back to the QueryCallback, the below example chains these as a set of tasks in an AsyncSerialTask and then calls the Execute method on the whole chain. The unit tests assertions are sprinkled throughout the chain so they are executed in the right places. Note how Task 7 actually encapsulates several lines of code that: a) depend on the results of the Async Queries above; and b) setup the IIndexPrice object that is needed for the IndexPriceService IsValidAsync and GetRateAsync method tests.

[TestMethod]

//[Ignore]
[Asynchronous]
public void TestAsyncIndexPriceService()
{
     _em = new DomainModel.DomainModelEntityManager();
     var task1 = AsyncSerialTask.Create();
     var task2 = task1.AddAsyncLogin(_em, new LoginCredential(null, null, null));
     var task3 = task2.AddAction(x => Assert.IsTrue(_em.IsLoggedIn));
     var task4 = task3.AddAction(x => Assert.IsTrue(_em.IsConnected));
     var task5 = task4.AddAsyncAction<AsyncEventArgs>((loginEventArgs, callback) =>
          _em.InitializeCacheAsync(callback,
          TestAsyncIndexPriceServiceParallelCallback));
     IIndexPrice index = null;
     var task6 = task5.AddAsyncQuery(x => _em.Pipelines);
     var task7 = task6.AddAction(x =>
     {
          var deal = Deal.Create(SampleData.SampleUser);
          var price = deal.DealPricings[0];
          deal.FlowDateStart = new DateTime(2009, 2, 10);
          deal.FlowDateEnd = new DateTime(2009, 2, 10);
          index = (IIndexPrice)price;
          index.Adder = 0M;
          index.HmlFlag = IndexHmlFlag.Medium;
          index.Pipeline = Pipeline.Fetch("BANANA");
     });
     var task8 = task7.AddAsyncAction<InvokeServerMethodEventArgs>((serialArgs, callback) => IndexPriceService.IsValidAsync(null, index, callback));
     var task9 = task8.AddAction(validArgs => Assert.AreEqual(true, Convert.ToBoolean(validArgs.Result)));
     var task10 = task9.AddAsyncAction<InvokeServerMethodEventArgs>((args, callback) => IndexPriceService.GetRateAsync(null, index, callback));
     var task11 = task10.AddAction(rateArgs => Assert.AreEqual(2M, Convert.ToDecimal(rateArgs.Result)));
     EnqueueCallback(() => task9.Execute(null, args => TestAsyncIndexPriceServiceCallback(args)));
}

//The following method is a workaround because the AsyncParallelTaskCompletedArgs do not inherit from AsyncEventArgs, which the AsyncSerialTask needs.
public void TestAsyncIndexPriceServiceParallelCallback(AsyncParallelTaskCompletedArgs args)
{
     // We passed this callback as input parm into the AsyncParallelTask
     var serialCB = args.ExecutionInput as AsyncCompletedCallback<AsyncEventArgs>;
     // Build new args, taking advantage of userState input argument.
     AsyncEventArgs newArgs = null;
     if (args.Ok)
     {
          // This is arbitrary - here we supply parallel task completion info ...
          newArgs = new AsyncEventArgs(args.CompletionMap);
     }
     else
     {
          // Also arbitrary - if parallel task failed provide some info ...
          newArgs = new AsyncEventArgs(args.Errors[0].Exception, false, args.Errors);
     }
     // Now call the serial task's callback action.
     serialCB(newArgs);
}

public void TestAsyncIndexPriceServiceCallback(AsyncSerialTaskCompletedArgs<InvokeServerMethodEventArgs> args)
{
     EnqueueTestComplete();
}

public static void InitializeCacheAsync(AsyncCompletedCallback<AsyncEventArgs> serialCallback, Action<AsyncParallelTaskCompletedArgs> completionAction)
{
     var task = AsyncParallelTask.Create();
     task.AddExceptionHandler(InitializationExceptionHandler);
     AddInitializationQueries(task);
     task.Execute(serialCallback, completionAction);
}

private static void AddInitializationQueries(AsyncParallelTask<object> task)
{
     task.AddAsyncQuery(1, x => _defaultManager.AccountingMonths);
     task.AddAsyncQuery(2, x => _defaultManager.DealTypes);
}

public static void InitializationExceptionHandler(AsyncParallelTaskExceptionArgs args)
{
     //ToDo: log exception?
     throw args.Exception;
}


Posted By: kimj
Date Posted: 29-Jul-2009 at 3:37pm
Very nice!  Thanks for posting.



Print Page | Close Window