Relevant Email Conversation

Coordinator
Jul 29, 2008 at 6:50 PM
Hello Ward,

   How are you doing WPF testing right now? In CSLA we're using NUnit to run non-Silverlight tests. The framework we have, UnitDriven is primarily helpful for Silverlight applications and has some .NET classes to allow you to run the same test code in NUnit as well (MSTest also theoretically, though we haven't tested that yet). But in our case the tests are still actually being run by NUnit and, you are correct, NUnit definitely does not start tests running on the UI thread.

   In fact, thank goodness it doesn't. If it did it would cause us to have to scrap NUnit altogether to use any WPF related code such as the background worker. The reason is simply because in NUnit when your test method is done executing your test is complete. If you want to do asynchronous processing then you have to block the thread that the test was run in until the background work has completed, however if you're running in the UI thread than any other background work trying to dispatch to the UI thread would result in a deadlock... which is why we had to create UnitDriven because the MSTest stuff that Microsoft created for Silverlight was running the tests in the UI thread but not giving us any means to asynchronously notify the framework that the test was completed. We were getting deadlocked. When using UnitDriven in .NET the same code that lets you notify the framework of a test completing asynchronously in Silverlight simply blocks the test thread in .NET.

   So in UnitDriven we have taken into account the problem of asserts happening asynchronously on the non-UI thread in .NET. Our solution is to create a "UnitTestContext" object which is accessible throughout the test (via lambdas or such). This context has assert methods right on it and if one of those asserts fails then it will save the exception rather than throw it immediately and before the test completes it will actually throw the exception back from the correct thread. This was a very tricky thing to figure out because we had to create the UnitTestContext object to behave differently in each framework. In silverlight you cannot throw the exception at all, you simple pass it back to UnitDriven via events. There is no such behavior in NUnit either, thus UnitDriven helps you work in both scenarios. Another interesting complication is the lack of an ability to create AppDomains in Silverlight. All of your tests must run in the same AppDomain which is totally different than NUnit.

   We actually have some examples of unit tests using the BackgroundWorker class, which when run in a WPF application will use the Dispatcher to dispatch the relevant delegates back to the UI thread to execute. Our unit test framework is able to take this sort of thing into account even though (since it's being driven by NUnit) there is no UI thread.

   Here is a pretty simple example of what I'm talking about with helpful code comments:
http://www.codeplex.com/UnitDriven/SourceControl/FileView.aspx?itemId=240788&changeSetId=20159

   That test runs in both .NET and Silverlight. In fact the exact same code file is linked and built in both of our test projects.

   I am curious about why you would want to create a Form in a unit test? In general I think creating a Form in a unit test is, perhaps, a little too broad of a test and the same results could probably be achieved by multiple smaller tests targeting the various logical aspects of the form. The view itself should be abstracted away from the unit tests not actually part of it... but it's not always that simple is it? If you gave me a small example of a potentially problematic unit test I would be happy see if I can get it to work somehow.

Thanks for the questions and feedback!

On Mon, Jul 28, 2008 at 9:53 PM, Rockford Lhotka wrote:

Hi Ward,

I'm copying Justin, as this is his brainchild J

We didn't design the framework with the intent of doing WPF testing, so it doesn't surprise me that it doesn't handle certain WPF-specific scenarios.

It is an open source project though, so if your subject matter expert is interested in enhancing UnitDriven to be WPF-friendly I'm sure they'd be more than welcome to do so!

Rocky

From: Ward Bell
Sent: Monday, July 28, 2008 9:45 PM
To: 'Rockford Lhotka'
Subject: Unit Testing and Silverlight

Rocky –

Great job on the Silverlight unit testing framework which, I am told, will likely save us a lot of time.

We have some "concern" with one aspect though (and this applies to WPF testing). I am told that it seems that  your tests do not attempt to execute on a WPF thread. There is some problem with WPF/Unit Testing interaction in which the proper synchronization context is not created. You would see the problem manifested if your test launched a WPF form,  fired up some async work from there, and then tried to run asserts on something returned in the callback; as I understand it, you would find that those asserts were not running on the WPF UI thread and could throw an exception.

I hope this makes sense to you … I'm getting the feedback second hand and have not been involved personally.   I can get more details if you're interested.

Not sure that this matters to you. It seems to matter to us.

Anyway, thanks for the insights,

Ward

From: Rockford Lhotka
Sent: Friday, July 25, 2008 8:01 AM
To: 'Ward Bell'
Subject: RE: No synchronous server calls in Silverlight. Does that bother you?

Hi Ward,

Yeah, this is challenging stuff being a mix of sync and async.

I understand what you'd like to do, but don't know if it is possible.

We've actually put our async approach (of not blocking the user) into both CSLA Light and CSLA .NET – so they can get the async stuff even in Windows Forms or WPF.

The unit testing is tough. We ended up writing our own Silverlight unit testing framework, and some helpers for MSTest/nunit. We contributed this to the community as an open source project: www.codeplex.com/UnitDriven 

The result is that we have (for the most part) unified unit tests that run in both .NET and SL, which is important for CSLA because the goal is compatibility of your business object code between the two environments.

Rocky