If you’ve been following the news on the upcoming Visual Studio 2012 Update 2 (currently in CTP4), you know that we now have a fully working Unit Tests framework for Windows Phone projects!
Well, this seemed like the perfect opportunity to finally create some unit tests for the Cimbalino Windows Phone Toolkit and test this new test framework, all at once!
Given that this post will require installing the VS2012.2 CTP 4, a non-final preview version software that has a “go-live” license, I think it’s only proper to apply the WOMM certification to it.
So bottom line, install it at your own risk!
So I started by installing the update, launch Visual Studio 2012, and create a new Windows Phone Unit Test App.
Then, I used NuGet to add a reference to the Cimbalino Windows Phone Toolkit and then added the following test class:
namespace Cimbalino.Phone.Toolkit.Tests.Converters
{
[TestClass]
public class ColorToBrushConverterTests
{
[TestMethod]
public void ConvertWithColorReturnsBrush()
{
var converter = new ColorToBrushConverter();
var expected = Colors.Blue;
var actual = converter.Convert(Colors.Blue, typeof(string), null, CultureInfo.CurrentCulture);
Assert.IsInstanceOfType(actual, typeof(SolidColorBrush));
Assert.AreEqual(((SolidColorBrush)actual).Color, expected);
}
}
}
This simple class will test the ColorToBrushConverter.Convert
method as to check for the proper creation of a SolicColorBrush out of a specific Color.
When I ran the test, this is what happened:
As you can see here, we got an “Invalid cross-thread access” error message; this is the result of all tests running on a special “test app” inside the Emulator, but the really bad news is that they all run in a background thread.
Apparently, if this was a Windows Store app we could just change the [TestMethod]
attribute with the proper [UITestMethod]
one as to mark the requirement of running the test in the UI Thread, but unfortunately, the attribute is currently missing from the Windows Phone test framework!
So I decided to fix that and create my very own UITestMethodAttribute
, and here it is:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class UITestMethodAttribute : TestMethodAttribute
{
public override TestResult[] Execute(ITestMethod testMethod)
{
TestResult[] result = null;
var ar = new AutoResetEvent(false);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
try
{
result = base.Execute(testMethod);
}
finally
{
ar.Set();
}
});
ar.WaitOne();
return result;
}
}
If you don’t like using the AutoResetEvent, then you can use this alternative version with the new Tasks:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class UITestMethodAttribute : TestMethodAttribute
{
public override TestResult[] Execute(ITestMethod testMethod)
{
var task = ExecuteOnUi(testMethod);
task.Wait();
return task.Result;
}
private Task<TestResult[]> ExecuteOnUi(ITestMethod testMethod)
{
var tsc = new TaskCompletionSource<TestResult[]>();
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
tsc.SetResult(base.Execute(testMethod));
});
return tsc.Task;
}
}
For a usage sample, please refer to the Cimbalino.Phone.Toolkit.Tests project!
Other approaches to solve this issue can be found in this post by Joost van Schaik or this gist from Jake Ginnivan, both relying on just running the necessary code in the UI instead of the full test method as with the above approach.