Blog |
|
Testing Asynchronous WPF Application with NUnitDeveloping applications that need asynchronous execution is usually much more complicated then ones do not need it. Unfortunately, automated testing of such applications became even harder. Some time ago I experienced difficulties with testing asynchronous Google App Engine service that uses Task Queue. This time it’s WPF desktop application that performs most of its job in background PTL (Parallel Task Library) tasks. Disregarding not-important details I can describe it in the following way:
How was I going to test it?
Everything was fine in a theory, but the problem is that if you want your model to be accesible in many threads which are different from the main one you need to write code like this in C#:
1: public static readonly DependencyProperty MyPropProperty = DependencyProperty.Register("MyProperty", typeof(bool), typeof(MyModel)); 2: 3: public bool MyProp 4: { 5: get 6: { 7: (bool) (Dispatcher.CheckAccess() 8: ? GetValue(MyPropProperty) 9: : Dispatcher.Invoke((Func<DependencyProperty, object>) GetValue, MyPropProperty)); 10: } 11: set 12: { 13: if (Dispatcher.CheckAccess()) 14: SetValue(MyPropProperty, value); 15: else 16: Dispatcher.Invoke((Action<DependencyProperty, object>) SetValue, MyPropProperty, value); 17: } 18: } The code is pretty strait-forward and it works good in application, but when I tried to run it under NUnit test Dispatcher.Invoke just hangs because there was no synchronization context set. 1: private DispatcherFrame _dispatcherFrame; 2: 3: [SetUp] 4: public void BeforeTest() 5: { 6: 7: _dispatcherFrame = new DispatcherFrame(); 8: } 9: 10: private static readonly TimeSpan WaitTimeout = TimeSpan.FromSeconds(5); 11: 12: protected void WaitFor(params Task[] tasks) 13: { 14: bool timedOut = false; 15: _dispatcherFrame.Continue = true; 16: 17: new Task(() => 18: { 19: timedOut = !Task.WaitAll(tasks, WaitTimeout); 20: _dispatcherFrame.Continue = false; 21: }).Start(); 22: 23: Dispatcher.PushFrame(_dispatcherFrame); 24: 25: if (timedOut) 26: throw new InvalidOperationException("Waiting timeout"); 27: } 28: 29: [Test] 30: public void MyTest() 31: { 32: 33: var mocks = /* configure mocks */ 34: 35: using (controller = new MainController(mocks)) 36: { 37: Task[] firstBunchOfTasks = 38: new Task[] 39: { 40: controller.StartFoo(), 41: controller.StartDoo() 42: }; 43: 44: WaitFor(firstBunchOfTasks); 45: 46: // assert something at this point 47: 48: Task someOtherJob = controller.StartJob(); 49: 50: Task fooAgain = controller.StartFoo(); 51: 52: WaitFor(someOtherJob, fooAgain); 53: 54: // verify final result 55: } 56: } Such solution works fine for me but if you know more elegant approach or think it can be done in a completely different way, please share you thoughts with me. My brainbench test results on C# 4.0Just tried free brainbench test on C# 4.0. I dislike some questions they asked but I like result I reached - 100% correct answers:)
Here is the transcript Testing GAE Task Queue with jUnitIt is generally agreed that automated testing is extremely important for software development process. It is so, despite the actual product’s complexity. I personally think that the primary reason of automated tests usage is possibility to make changes to your code and quickly check whether the very basic business workflow still works. And because of that I dislike unit testing which I think makes sense not so much often and only to verify some of isolated components with complicated logic. Putting effort into unit-testing 50-60-70-80-90% coverage and even more of application code is in vain - it takes too much time and it causes a problem it’s supposed to solve - when you have so much percentage of unit-tested code you are not able to make changes to your software quickly, 5 minutes refactoring causes 1 hour of fixing tests. If you choose to disable automatically asynchronous tasks running to be able to manually check that everything is scheduled correctly and then run the async jobs TaskQueueRunner provides two overloads of processTasks static method. Too many emails that are not communication messagesWe usually do not realize the amount of information we get every day, every hour, every minute. Me personally didn't really take it into consideration until recently when I returned back from one-week vacation :) Yes during it I didn't have any access to the Internet :) And to be honest, I do not have such vacations often. The other fact I learned from the HUGE amount of emails, rss updates, social network messages and etc was that such information capacity is much higher than it was 2 years ago and enormously higher than 5 year ago. |
|