views:

86

answers:

2

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  A: 

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

ktutnik
Unfortunately that's what my solution boiled down to in the end. See my updated post.
Oliver Weichhold
+1  A: 

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.

Alex Paven
Excellent suggestion. Reading and using that library is a real eye opener.
Oliver Weichhold