As everyone knows Microsoft didn’t exactly have test driven development as their main focus when creating Silverlight.
Nowadays whilst testing in Silverlight has greatly improved, with both Microsoft and the community providing better test options for Silverlight, the situation is still not as good as we are used to in the rest of the .NET world. For example, it’s a real pain not being able to run NCrunch in Silverlight or use xUnit or NUnit for my tests (there is an NUnit for Silverlight project but it’s out of date at the moment).
I currently use Silverlight Unit Tests (part of the Silverlight Toolkit SDK), StatLight with TeamCity integration and AgUnit for ReSharper as the test runner within Visual Studio.
Here’s how it’s done:
Create a Silverlight Application which will be your main XAP file project. The trick is that this will act as a shell containing purely your views and your app.xaml file. You'll probably want to create it with an ASP.NET Web Server Host project.
Next up create a Silverlight Class Library that we’ll call our Presentation Layer. This will contain all the “code” such as your commands, converters and view models, etc.
Now we can add a Silverlight class library to our solution that will contain our tests.
UI Prototype
Code to Interfaces
First up define the interface to your ViewModel based on our UI prototype.
namespace SilverlightValidation.Interfaces
{
public interface IUserViewModel : INotifyDataErrorInfo,
INotifyPropertyChanged,
IUserModel
{
bool IsChanged { get; }
ICommand OkCommand { get; set; }
ICommand CancelCommand { get; set; }
}
public interface IUserModel
{
string Username { get; set; }
string Email { get; set; }
string Password { get; set; }
DateTime? DateOfBirth { get; set; }
string Description { get; set; }
}
public interface ICloneable<T>
{
T Clone();
}
}
Fluent Assertions
For our tests I use the Fluent Assertions library to help reduce code and make the tests easier to read.
Fluent Assertions on Codeplex: http://fluentassertions.codeplex.com/
ShouldRaisePropertyChangeFor
A good example is the Event Monitoring provided by Fluent Assertions, which internally contains an assert check for the Username Property Changed event.
var subject = new UserViewModel();
subject.MonitorEvents();
subject.Username = "adminSH";
subject.ShouldRaisePropertyChangeFor(x => x.Username);
View Model Tests
Helper for tests https://gist.github.com/2624206
A helper class that acts as a factory for providing pre-built objects such as a default ViewModel.
Constructor tests https://gist.github.com/2624197
When using Dependency Injection we need to check the arguments in our constructor are valid.
Commands tests https://gist.github.com/2624192
Check the commands are executable and execute as required. For example, the OK command which might normally save to the database could be using a database service which could be mocked out by the test to check it has been executed.
INotifyDataErrorInfo tests https://gist.github.com/2624201
Validation rules need to be adhered to so we’ll need to test data values pass, fail and boundary check our validation logic.
INotifyPropertyChanged tests https://gist.github.com/2624203
Obviously we’re using data binding in our view so we need to make sure property change notification events are being fired as we update our properties. I love the Fluent Assertions library for this, it gives a very clean and read to easy syntax for the tests – great framework!
Test Runner Output in Visual Studio
TeamCity CI Server Output
With the StatLight tool added to the repo a simple build step can be added to TeamCity:
StatLight.exe -d="SilverlightValidation\SilverlightValidation.Tests\bin\Release\SilverlightValidation.Tests.dll" –teamcity
StatLight Output
If you want to manually run StatLight outside of the Visual Studio process:
Browser Test Runner
Screenshot of working version
This online demo is here: http://stevenhollidge.com/blog-source-code/slvalidation/
TODO: UI test recording (TestComplete or Telerik)
Source code
http://stevenhollidge.com/blog-source-code/SilverlightValidation.zip
No comments:
Post a Comment