7 January 2009
Did you know that you can run NUnit tests with the Silverlight unit test framework? In this short guide, I talk about updating NUnit to build for Silverlight, wiring up test projects, and a download with everything you need to get started.
This isn't a "metadata redirection" trick - but the actual NUnit assertions and metadata running inside the Silverlight unit test engine. This took about 15 minutes to implement from start to finish - shorter than the amount of time it'll take me to publish this post.
Though NUnit is great for legacy components and tests, I strongly recommend using the built-in Visual Studio metadata for most projects. The metadata is used by enough folks throughout Microsoft and the industry to be well-supported, tested, familiar, and not require the custom unit test provider hookup in your test projects.
That said, I do hear about legacy business objects and NUnit tests that devs would like to be able to verify and run in the browser + Silverlight environment.
You can read about NUnit attributes and assertions in the official documentation. So, here goes...
Inside the traditional NUnit source download, there's a sample called "Money" that tests a simple interface and types. Here's that "Money" project running on OS X/Safari, via the Silverlight unit test framework and NUnit:
"Money" sample test project: Click on the image or here to run the Silverlight test application on your machine. Tests will start in ~5 seconds.
If you have a set of legacy business objects and associated NUnit tests, you'll find it easy to run them within Silverlight now.
To further demonstrate the compatibility here, this is the "NUnitTests" test project that validates the core NUnit framework and its assertions, running inside Chrome:
"NUnitTests" that validate the NUnit framework. Click on the image or here to run the tests.
When designing the Silverlight unit test framework, it became clear that there were three or four distinct test engine components that could be combined into a single test system. Yet, they were distinct enough to allow alternative implementations and extensions to be built.
The typical test application .XAP file ends up containing the general Silverlight unit testing engine (that performs test execution, and is very different from typical engines in that it runs on the UI thread and is synchronous), your actual tests marked with the appropriate metadata, and then the metadata and unit test assertions that you're using.
Inside the unit test engine, there's a base test harness class, and then the UnitTestHarness implementation that does most of the heavy lifting. A set of interfaces abstract out the reading and processing of unit test metadata. Interfaces aren't always a great answer, but the value added in this case.
The metadata/assertion implementation that you use (NUnit or VSTT, for example) takes care of throwing exceptions when assertions fail, that the framework then processes in a generic way.
The Silverlight unit framework ships with the same metadata used in the Visual Studio team system's unit test framework, making it easy to move between desktop and Silverlight application and test development. A "VsttProvider" sits between the Visual Studio metadata and the actual unit test engine, and ships in the Microsoft.Silverlight.Testing assembly.
OK. That's a mouthful, but it means that you can implement your own metadata provider to support running other unit tests. Since NUnit and VSTT are so similar, this was easy - but more intricate frameworks might need to modify or extend the actual unit test system to provide the right experience.
NUnit is relatively old; it is from a different era of .NET development. NUnit utilizes the old .NET Hashtable and ArrayList types.
Also, the .NET framework base class libaries included in Silverlight are a subset, rely more on .NET 3.5 features, and exclude some of the older types.
To easily support building NUnit with the Silverlight subset of the framework, here's the list of changes I needed to make to the NUnitFramework project:
So, I added a small "CompatibilityShims" Silverlight C# library project to the solution that included Hashtable, ArrayList, and SerializableAttribute.
Unlike standard NUnit test projects, you will need to create an actual Silverlight application project for your tests. Once you create a new empty app, here's what you should do:
Here's what the startup code should look like for the test application:
private void Application_Startup(object sender, StartupEventArgs e) { UnitTestSystem.RegisterUnitTestProvider(new NUnitProvider()); RootVisual = UnitTestSystem.CreateTestPage(); }
The code is similar to the regular Silverlight unit test startup code that you use for VSTT tests, except it first registers the NUnitProvider.
You can build and run the Silverlight application like any other: just press F5 and the tests will run!
Since the unit test engine is metadata-agnostic, it handles all the advanced asynchronous and Silverlight-specific test functions. Many of the core features specific to the Silverlight framework work with NUnit, therefore.
You'll find that you can use:
I'm offering this as a proof-of-concept, unsupported download. Inside you'll find everything that you need to explore the concept.
Hope this helps!
Jeff Wilcox is a Software Engineer at Microsoft in the Open Source Programs Office (OSPO), helping Microsoft engineers use, contribute to and release open source at scale.