Integration Testing a ViewModel that calls WCF Services asynchronously in a WPF MVVM Application
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 Ob开发者_Python百科servable 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");
}
});
}
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
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.
精彩评论