3
votes

The Silverlight Toolkit contains Unit Testing Functionality that allows to test classes such as the ViewModels in a MVVM application that invoke remote Services asynchronously.

I would like to be able to perform my ViewModel Integration Tests against the actual services instead of mocked instances.

Is there any support for asynchronous Unit/Integration Testing for WPF Applications?

Update:

At the end of the day my solution combined the suggestions of ktutnik and Alex Paven. I wrote a tiny helper class that adds some syntactic sugar:

public static class AsyncMethod
{
    public delegate void AsyncMethodCallback(AsyncMethodContext ctx);

    public static void Call(AsyncMethodCallback cb)
    {
        // create the sync object and make it available via TLS
        using (var syncObject = new AutoResetEvent(false))
        {
            // call the decorated method
            cb(new AsyncMethodContext(syncObject));
        }
    }
}

/// <summary>Asnc Method Callback Synchronization Context</summary>
public class AsyncMethodContext
{
    public AsyncMethodContext(EventWaitHandle syncObject)
    {
        this.syncObject = syncObject;
    }

    private readonly EventWaitHandle syncObject;

    /// <summary>
    /// Waits for completion.
    /// </summary>
    public void WaitForCompletion()
    {
        syncObject.WaitOne();
    }

    /// <summary>
    /// Signals the current operation as complete
    /// </summary>
    public void Complete()
    {
        syncObject.Set();
    }
}

Here's a sample test case combined with the utilization of the Microsoft Rx Extensions:

[TestMethod]
public void TestGuestLogin()
{
    AsyncMethod.Call((ctx) =>
    {
        var vm = ServiceLocator.Get<LoginDialogViewModel>();

        // setup VM data
        vm.Username = "guest";
        vm.Password = "guest";
        vm.AutoLogin = false;
        GenericInfoEventArgs<LoginDialogViewModel.LoginRequestResult> loginResult = null;

        // pre-flight check
        Assert.IsTrue(vm.LoginCmd.CanExecute(null));

        // create Observable for the VM's LoginRequestComplete event
        var loginEvent = Observable.FromEvent<GenericInfoEventArgs<LoginDialogViewModel.LoginRequestResult>>(vm, "LoginRequestComplete").Do((e) =>
        {
            Debug.WriteLine(e.ToString());
        });

        // subscribe to it
        var loginEventSubscription = loginEvent.Subscribe((e) =>
        {
            loginResult = e.EventArgs;

            // test complete
            ctx.Complete();
        });

        // set things in motion
        using (loginEventSubscription)
        {
            vm.LoginCmd.Execute(null);
            ctx.WaitForCompletion();

            Assert.IsTrue(loginResult.Info.Success, "Login was not successful");
        }
    });
}
2

2 Answers

3
votes

I was hunting for a long time for this feature but unlucky yet.

Not really a clean solution but it is work for me. I usualy used ManualResetEvent so the testing process not fall down until asynchronous done. Here is the idea:

//set false for initial state
resetEvent = new ManualResetEvent(false);
//do the test
myObjec.MakeMeHappyAssync();
//just wait until its state set 
//when your call done
resetEvent.WaitOne();
//do assertion here

And somewhere in on your Complete Method or Fault Method you simply call

resetEvent.Set();

Anyway if you found any new information about the feature please let me know

Best Regard

1
votes

You could look into Reactive Extensions, which are now included in .Net Framework 4, assuming you're using it; there are versions for 3.5 and Silverlight as well. They allow for some nice asynchronous coding, I've used them in unit testing before. See here for a blog article discussing it.