Sunday, March 28, 2010

Short form: TDD Kata for MVVM on Windows Phone 7

Can you complete the kata in under 60 minutes?

* What is a TDD kata? See the Calculator kata
* This is the text-only version. If you're trying this for the first time, work through the detailed version with code snippets.

a) Install VS 2010 Express for Win Phone 10, and add the unit testing components. [Details].
b) Create a Windows Phone 7 application (a single project, single solution--required by the unit testing framework).
c) Create a code sub-folder (name it whatever you like.)
d) Within the code folder, create sub-folders for Domain, Repository, ViewModel, ThirdParty, and Tests.Unit.
e) Copy/paste the ButtonService.cs class code (from Details link, above) into the ThirdParty folder to provide a Command dependency property.
f) This project is now configured for wp7 unit testing and ICommand data binding (so you may want to save a copy of it for use as a template.)

Set your watch, and begin the kata:
1) Create a test class, CustomerViewModelTests, and add references to the unit test framework.
2) Create a test setup method, in which you instantiate a FakeCustomerRepository class to the ICustomerRepository instance variable.
3) Test that a (new) Customer domain entity and that ICustomerRepoository are passed as constructor parameters to CustomerViewModel.
4) Test that Customer has FirstName/LastName properties, and that CustomerViewModel has FirstName/LastName properties whose values are equal (hint: they WRAP, not duplicate, the Customer properties).
5) Test that a new method CustomerViewModel.VerifyPropertyName(string propertyName) throws an exception if a property name passed to it doesn't exist.
6) Test that CustomerViewModel is instance of type INotifyPropertyChanged.
7) Test that each time properties of the Customer domain entity are changed
* that the PropertyChangedEvent has been raised,
* that the equivalent view model properties have also changed
8) Refactor (move) the INotifyPropertyChanged interface and related methods to ViewModelBase, and then change CustomerViewModel to extend ViewModelBase. Ensure that all tests are still passing.
9) Create another test class, CustomerSaveCommandTests.cs, and add references to the unit test framework.
10) In CustomerSaveCommand, duplicate the ICustomerRepository instance variable and test setup method from CustomerViewModel.
11) Test that Customer and ICustomerRepoository are passed as constructor parameters to CustomerSaveCommand.
12) Test that CustomerSaveCommand is instance of type ICommand.
13) Reference CustomerSaveCommand as a new property of CustomerViewModel, the SaveCommand property.
14) Return to the CustomerViewModelTests class, and verify that customerViewModel.SaveCommand.CanExecute(null) returns false when the nested Customer FirstName and LastName properties are null or empty, else returns true.
15) Create test for CustomerViewModel.CustomerSaveCommand.Execute() method which verifies that
the nested _customerRepository.SaveCustomer() method had been called. Since you are using a fake instead of a mock, add a boolean property, FakeCustomerRepository.SaveMethodCalled which verifies that the repository Save method has been called.
16) Ensure that all tests are passing.

POST-SCRIPT: Connecting the presentation layer to the view model
17) Switch off the unit testing framework in the MainPage.xaml.cs class constructor (set runUnitTests to false).
18) Go to MainPage.xaml ann add an XML namespace reference to the ViewModel namespace.
19) Add another XML namespace reference to the ThirdParty namespace.
20) In the code-behind (MainPage.xaml.cs), in the constructor, instantiate CustomerViewModel (with a Customer parameter whose FirstName/LastName properties are empty) and assign the view model instance to this.DataContext.
21) In MainPage.xaml, in the lower Grid element, drag 2 TextBox controls and a Button to the Phone GUI design surface.
22) Add two-way binding between each TextBox and the corresponding properties of CustomerViewModel.
23) Add a customer property thirdParty:ButtonService.Command="{Binding Path=SaveCommand}" to the Button (i.e. the path is the name of the CustomerViewModel.SaveCommand property.)
24) Set a breakpoint on FakeCustomerRepository.SaveCustomer()
25) Run the Windows Phone emulator.
26) Add FirstName and LastName values.
27) Verify that when the Button is clicked, that this method is called with a Customer parameter containing the FirstName/LastName values you entered.

You're done!

1 comment:

Smile said...

I agree with Phil, it looks cleaner and more professional. Thanks you!
led flashlight