This project is read-only.

How to: Unit Test a Presenter

The View-Presenter pattern separates the responsibilities for the visual display and the event handling behavior into different classes. The separation of these concerns helps you test your presentation logic without requiring a specific visual user interface implementation.
This topic describes how to unit test a presenter without a visual user interface implementation.

Prerequisites

This topic assumes that you have an existing Web client solution. For information about how to create a Web client solution, see How to: Create a Web Client Solution.

Steps

You can use the View-Presenter pattern to test the presenter independently of a specific view implementation. Isolating the tests for the presenter is useful because you can focus your attention on testing the presenter class and not its dependencies. You can achieve isolated testing by replacing the presenter's dependencies (for example, its view) with mock implementations.
If you create a presenter class that has a reference to a view implementation class, that view implementation class is required for the presenter's unit tests. To avoid the reference to the view implementation class, you define an interface for the view and reference the view interface in the presenter. By doing this, you can easily create a mock implementation of your view for your presenter's unit tests (the mock implementation implements the view interface). You use the mock view to test the interaction between the presenter and the view.
The following procedure describes how to create a mock view.

To create a mock view
  • Define a new class that implements the view's interface.
Note:
The Add Page (with presenter) recipe, the Add Master Page (with presenter) recipe, and the Add User Control (with presenter) recipe automatically generate a mock view class if you have a test project for the business module on which the recipe is executed. The mock view is defined in the same file that contains the unit tests for the presenter.
  • Implement the methods defined in the interface and provide additional elements to allow you test the presenter interaction with the view. For example, you can add public properties or fields to your mock view to test whether the presenter actually sets a property value in the view.
  • The following code shows a mock view that allows you to test that the Customer property is set. Note that the ISummaryView interface (implemented by the mock and the real view) only defines the setter of the Customer property, but the mock implementation also includes a getter so the value can be retrieved in the unit tests of the presenter.

internal class MockSummaryView : ISummaryView
{
    private Customer _customer;

    #region ISummaryView Members

    public Customer Customer
    {
        get { return _customer; }
        set { _customer = value; }
    }

    #endregion
} 

public interface ISummaryView
{
    Customer Customer { set; }
} 

The following procedure describes how to create mock classes for other dependencies of the presenter.

To create mock classes for other dependencies of the presenter
  1. If your presenter contains other dependencies, such as services or controllers, create mock classes for these dependencies. To do this, create an interface for each dependency, and then implement the interface in your mock implementation (as you did for your mock view).
  2. If you must keep a reference to the concrete class in the presenter, you can create a mock class that extends the real class and overrides members. If you use this approach, you must have the real implementation of the dependency when you create the presenter.For example, the following code shows a mock implementation for an application controller. The mock class extends the real implementation class, CustomersController.

internal class MockCustomersController : CustomersController
{
    public Customer InnerCurrentCustomer = null;
    public bool ApproveCurrentCustomerCalled = false;
    public bool ApproveAnotherCustomerCalled = false;

    public override Customer CurrentCustomer
    {
        get { return InnerCurrentCustomer; }
    }

    public override void ApproveCurrentCustomer()
    {
        ApproveCurrentCustomerCalled = true;
    }

    public override void ApproveAnotherCustomer()
    {
        ApproveAnotherCustomerCalled = true;
    }
} 

You can use the MockCustomersController class to test the interaction of the presenter with the CustomersController class. It overrides methods that the presenter calls and sets public flags that you query in your unit tests. You use these flags to verify whether methods were invoked. The mock class also contains a public field named InnerCurrentCustomer that you can set in your unit tests code. You use this property to set the instance of a CurrentCustomer object that the real controller class obtains internally (for example, through a data access layer).

Note:
The Add Business Module recipe generates a mock module controller class you can use in your presenter's unit tests. The mock module controller is stored in the Mocks folder of the module's test project.

The following procedure describes how to implement the unit tests for the presenter.

To implement unit tests for the presenter
  1. Use the mock objects you created in the previous procedures to create your unit tests. For example, the following code shows a unit test that demonstrates the usage of a mock view and a mock module controller. The unit test verifies that the presenter retrieves a Customer instance from the controller when the presenter's OnViewLoaded method is invoked.

[TestMethod]
public void OnViewLoadedCallsControllerCurrentCustomerAndViewSetCustomer()
{
    MockSummaryView view = new MockSummaryView();
    MockCustomersController controller = new MockCustomersController();
    controller.InnerCurrentCustomer = new Customer();
    SummaryViewPresenter presenter = new SummaryViewPresenter(view, controller);

    presenter.OnViewLoaded();

    Assert.IsNotNull(view.Customer);
    Assert.AreSame(controller.CurrentCustomer, view.Customer);
} 

This unit test creates both a mock view and mock controller. It uses the InnerCurrentCustomer property of the mock controller to set an instance of the customer object. It creates a presenter instance and calls the OnViewLoaded method and then performs two assertions:
  • Assert.IsNotNull(view.Customer). This assertion verifies that the presenter set a valid Customer instance in the Customer property of the view.
  • Assert.AreSame(controller.CurrentCustomer, view.Customer). This assertion verifies that the Customer instance set in the view is the same one that was returned by the CurrentCustomer property of the controller.
Note:
Using descriptive names for test methods is a recommended practice when writing unit tests. By doing this, developers can quickly understand the purpose of the test.

Outcome

You will have the following elements in your solution:
  • A mock view
  • Mock classes for dependencies of the presenter
  • Unit tests for the presenter

Next Steps

If you are using test-driven development (TDD), the typical task to perform after you create unit tests for the presenter is to implement the presenter.

Last edited Nov 20, 2007 at 2:28 PM by ejadib, version 2

Comments

No comments yet.