1. Problem
You want to write an application and test its logic by using a unit test, instead of using the F5 debug approach.
2. Solution
You must write your
application by using the MVVM pattern, then you will be able to write
Unit Test for each ViewModel. To test your ViewModels, you need to use
the Silverlight Unit Test Framework tweaked for Windows Phone 7 by Jeff
Wilcox.
3. How It Works
Unit tests are important
for testing the singular functionality of your classes. In this recipe,
you will build on Recipe 1 by creating logic for the SaveCommandExecute
method. You will then create a test class with two test methods, one
that always fails and another that always works. This way, you will
learn how to run tests on your ViewModel and how to write them, with the
scope of automatically test your business logic without any needs of
interaction by you with the user interface (this is not completely
exact, because Silverlight Unit Test Framework requires a couple of tap
by you to run the Test).
4. The Code
Because the scope of this recipe is to show you how to unit test your Windows Phone applications, we added dummy logic to ViewModel, introducing the enumeration states:
public enum States : uint { Saved, Unsaved};
and a property inside MainPageViewModel of this type
...
#region State Property
/// <summary>
/// The <see cref="State" /> property's name.
/// </summary>
public const string StatePropertyName = "State";
private States _state = States.Unsaved;
/// <summary>
/// Gets the State property.
/// </summary>
public States State
{
get
{
return _state;
}
set
{
if (_state == value)
{
return;
}
var oldValue = _state;
_state = value;
// Update bindings, no broadcast
RaisePropertyChanged(StatePropertyName);
}
}
#endregion
...
As you can see, this
property notifies the interface that a change has occurred, because when
you save an object, it's good practice to let the user know what is
being done.
Our last change to MainPageViewModel for this recipe is in SaveCommandExecute, which checks for the state of the view model and sets the State
property to "saves" or "unsaves" data (of course, the logic that we
show you its really simple but only because we use it for a didactical
purpose)
private void SaveCommandExecute()
{
State = (this.Amount == 0 || string.IsNullOrEmpty(Motivation))
? States.Unsaved : States.Saved;
}
Now that you have logic inside your ViewModel, you are ready to test it. Create a folder inside your project with the name UnitTests and add a class inside it named MainPageViewModelTest.
This class must be decorated with the TestClass attribute and needs to inherit from the SilverlightTest class contained in the namespace Microsoft.Silverlight.Testing, which is inside the assembly Microsoft.Silverlight.Testing.dll. We added three methods inside this class— TestSaveAlwaysFails, TestSaveOk, and TestSaveKo—decorating them with the TestMethod
attribute. As you can guess from the names, the first test always
fails, the second test results in a successful save, and the last
results in an incorrect save
[TestClass]
public class MainPageViewModelTest : SilverlightTest
{
[TestMethod]
public void TestSaveAlwaysFails()
{
MainPageViewModel vm = new MainPageViewModel();
vm.Motivation = string.Empty;
vm.SaveCommand.Execute(null);
Assert.IsTrue(vm.State == MainPageViewModel.States.Saved);
}
[TestMethod]
public void TestSaveOk()
{
MainPageViewModel vm = new MainPageViewModel();
vm.Motivation = "Shopping";
vm.Amount = 200;
vm.SaveCommand.Execute(null);
Assert.IsTrue(vm.State == MainPageViewModel.States.Saved);
}
[TestMethod]
public void TestSaveKo()
{
MainPageViewModel vm = new MainPageViewModel();
vm.Motivation = string.Empty;
vm.SaveCommand.Execute(null);
Assert.IsFalse(vm.State == MainPageViewModel.States.Saved);
}
}
The last thing you need to do is
to set the entry point for your suite of tests. Load the test execution
page just after loading the main page of the application, as follows:
public MainPage()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
SystemTray.IsVisible = false;
var testExecutionPage = UnitTestSystem.CreateTestPage() as IMobileTestPage;
BackKeyPress += (k, ek) => ek.Cancel = testExecutionPage.NavigateBack();
(Application.Current.RootVisual as PhoneApplicationFrame).Content =
testExecutionPage;
}
Now you are ready to test your application.
5. Usage
Run the project by using
Visual Studio, targeting the emulator (if you run it on the device
itself, some text blocks will be too small to read well, but we think
that by the quantity of information shown inside the test page, there is
nothing more to do). Wait a few seconds while the test page runs (see Figure 1). Then look for the result (see Figure 2).
As planned, one test failed, and other two passed (That in Test Driven
Develepement TDD traducts in "correct the bug then run the test again")