Web Client Software Factory
September 25, 2006
Hi guys! I’m here at Microsoft, Redmond, working on an amazing project the Web Client Software Factory with Pattern & Practices team. In this factory we’re going to include
-
Scenario documentation
-
Architecture documentation
-
Design patterns
-
How-tos
-
Reference Implementations
-
Training content (Hands-On-Labs, demos, etc)
Also we’re going to provide UIP migration guidance to our new Page Flow structure. Please help us by filling this questionnaire http://www.zoomerang.com/survey.zgi?p=WEB225N5A8M9Q4.
The Vision & Scope document for this project is also available here (SCP-WCSF-VisionScope.ppt-V1.2-EA.ppt).
To check our current priorities visit this link (http://www.codeplex.com/Wiki/View.aspx?ProjectName=websf&title=Current%20Priorities)
Finally, I’m happy and proud to be part of a team with guys like:
-
Blaine Wastell
-
Prasad Paluri
-
Terrence Cyril
-
Tim Osborn
-
Dragos Manolescu
So stay tune to our workspace on CodePlex, because our first weekly drop is out and available to the public.
Thanks!
How-To: Write MVP using TDD
September 1, 2006
Introduction
In this How To I want to show how to write code using TDD and leveraging the MVP pattern.This sample uses CAB and SCSF.
The requirement
Retrieve contacts and put them in a datagrid when the Load button is pressed.
- The user will be able to filter by Name, Last Name or Phone Number
- The number of contacts found cannot be greater than 10. If it is, we should display a message (“Too many contacts, please narrow your search”)
- If no contacts were found, we should display a message (“No contacts found”).
Using Mock Objects to fake the view and services
In the MVP pattern, the presenter knows about the view by its interface. To have a better separation of responsabilities, we use “services” that performs some logic. The presenter will also know about the services by their interfaces.
As we want to test interactions that happens in the presenter without testing the view or the services, we need to fake them.
Said that, the solution includes a few Mock Objects. These are:
- A Mock View
class MockView : IFindContactView
{
public bool DisplayContactsCalled;
public bool ShowMessageCalled;
public void DisplayContacts(List<Contact> contacts)
{
DisplayContactsCalled = true;
}
public void ShowMessage(string message)
{
ShowMessageCalled = true;
}
}
- A Mock Service
class MockService : IContactManager
{
public bool FindContactsCalled;
public int NumberOfResults = 0;
public List<Contact> FindContacts(string name, string lastName, string phoneNumber)
{
FindContactsCalled = true;
List<Contact> contacts = new List<Contact>();
for (int i = 0; i < NumberOfResults; i++)
{
contacts.Add(new Contact("John", "Doe", "43321232-23123"));
}
return contacts;
}
}
Note: In the MockService I included some additional methods for testing propose for example NumberOfResults, this method will generate the desired number of results.
Also the MockObjects includes flags to check the interaction as I mentioned above, these flags are like SomeMethodCalled that will help us when writing assertions.
Excercise
Step 1: Creating the test for the Simplest Scenario
The simplest scenario is when you call the Presenter.FindContacts method the FindContacts method of the service and the View.DisplayContacts method should be called.
- Open the FindCustomerViewPresenterFixture.cs
- Add the following code (in the FindCustomerViewPresenterFixture class)
[TestMethod]
public void ContactsDisplayedWhenApply()
{
mockService.NumberOfResults = 1;
presenter.FindContacts("john", null, null);
Assert.IsTrue(mockService.FindContactsCalled);
Assert.IsTrue(mockView.DisplayContactsCalled);
}
3. Now build the project, it should fail.
4. Open the FindContactViewPresenter.cs
5. Add the following code to the FindContacts method
public void FindContacts(string name, string lastName, string phoneNumber)
{
return;
}
6. Build the solution, it should run successfully
7. Run the test, it will fail.
What we have here? This kind of work help us to show our intention. This baby-steps will generate more consistent code. So the next step will be refactoring to pass the test.
Step 2: Refactoring the method to pass the test
- Open the FindCustomerViewPresenter.cs
- Add the following code on the FindContacts method
public void FindContacts(string name, string lastName, string phoneNumber)
{
List<Contact> contacts = this.ContactManager.FindContacts(name, lastName, phoneNumber);
View.DisplayContacts(contacts);
return;
}
3. Build the solution
4. Run the tests, now it should pass.
Step 3: Creating the test for no contacts found
Now we’re going to create the test method that will check that a message is displayed when the number of contacts is less than 1.
- Open the FindCustomerViewPresenterFixture.cs
- Add the following code (in the FindCustomerViewPresenterFixture class)
[TestMethod]
public void ContactsDisplayedWhenApply()
{
mockService.NumberOfResults = 0;
presenter.FindContacts(null, null, null);
Assert.IsTrue(mockService.DisplayMessageCalled);
Assert.IsFalse(mockView.DisplayContactsCalled);
}
3. Now run the test, it should fail.
4. Open the FindContactViewPresenter.cs
5. Add the following code to the FindContacts method
public void FindContacts(string name, string lastName, string phoneNumber)
{
List<Contact> contacts = this.ContactManager.FindContacts(name, lastName, phoneNumber);
if(contacts.Count < 1)
{
View.DisplayMessage("No contacts found!");
return;
}
View.DisplayContacts(contacts);
return;
}
6. Run the test, it will run successfully
Step 4: Creating the test when more than 10 contacts are found
Now we’re going to create the test method that will check that a message is displayed when the number of contacts is less than 1.
1. Open the FindContactViewPresenter.cs
2. Add the following code on the FindContactViewPresenterFixture class
[TestMethod]
public void MessageIsDisplayedWhenMoreThan10ContactsAreFound()
{
mockService.NumberOfResults = 11;
presenter.FindContacts(null, null, null);
Assert.IsTrue(mockView.ShowMessageCalled);
Assert.IsFalse(mockView.DisplayContactsCalled);
}
3. Build & run the test, it should fail.
4. Add the following code on the FindContactViewPresenter class (FindContactViewPresenter.cs)
public void FindContacts(string name, string lastName, string phoneNumber)
{
List<Contact> contacts = this.ContactManager.FindContacts(name, lastName, phoneNumber);
if (contacts.Count < 1)
{
View.ShowMessage("No contacts found");
return;
}
else if (contacts.Count > 10)
{
View.ShowMessage("Too many contacts found, please narrow your search");
return;
}
View.DisplayContacts(contacts);
return;
}
5. Build & run the test, it should pass
You can download the code from here
Conclusions
We’ve fully implemented the requierement and the presenter has the expected behavior. We wrote consistent, robust and high quality code. The core idea of this is being consistent and develop using baby-steps to increase code quality.
Feedback is always welecome/expected