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

  • Guidance Packages

  • 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:

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.

  1. Open the FindCustomerViewPresenterFixture.cs
  2. 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

  1. Open the FindCustomerViewPresenter.cs
  2. 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.

  1. Open the FindCustomerViewPresenterFixture.cs
  2. 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