For example, I will take Northwind database. I generally use LINQ for accessing database so I have created a dbml for the whole bunch of Northwind database.
Here we can represent data layer as our model. Frankly speaking, model represents the datalayer and datalayer could be your traditional classes to access database or some services to access database. Here we will use LINQ classes for our datalayer.
The web interface is very simple in order to make the illustration purpose easy. Let's talk about our web interface. It will load with all categories and for category selection; it will show the list of products under the selected category. It should have one dropdownlist to hold all the categories. When user selects the category from category listbox, a gridview will be shown with the all products under the category. It's obvious that we have two events; one is pageload on which all the categories will be shown in the category list; another is selected index change of the dropdownlistbox on which the products will be populated for the selected category in the products gridview. Also there should be some list/collection classes to hold the list of category/product.
So for our view, we will create the interface and one delegate. The code is shown below.
public delegate void CategoryChangeEventHandler(object source, CategoryEventArgs e);
public interface IProductListing
{
IEnumerable<Category> Categories { get; set; }
IEnumerable<Product> Products { get; set; }
event EventHandler ListingCategory;
event CategoryChangeEventHandler ChangeCategory;
}
The code is very simple to understand. We declare two enumerable interfaces to hold the list of categories/products and two events; one is listing of category and another is category changing. In ChangeCategory event, we declare a custom eventargs class to hold the selected category id. The code for CategoryEventArgs is shown below.
public class CategoryEventArgs : EventArgs
{
private Int16 _CategoryID;
public CategoryEventArgs(Int16 CategoryID)
{
this._CategoryID = CategoryID;
}
public Int16 CategoryID
{
get
{
return this._CategoryID;
}
set
{
this._CategoryID = value;
}
}
}
Let's show the code for the presenter class. Presenter class is responsible for doing something when view raises event and presenter will respond to the event. To get the view instance, we pass the view through the presenter's constructor. This method is called constructor injection – a Dependency Injection method. Then we will subscribe the view events with methods declared in the presenter. The code is shown below.
public class ProductListingPresenter
{
IProductListing _view;
public ProductListingPresenter(IProductListing view)
{
this._view = view;
this._view.ListingCategory += this.OnCategoryListing;
this._view.ChangeCategory += this.OnCategoryChanged;
}
private void OnCategoryListing(object source, EventArgs e)
{
NorthwindDataContext oDataContext = new NorthwindDataContext();
this._view.Categories = from category in oDataContext.Categories
select category;
}
private void OnCategoryChanged(object source, CategoryEventArgs e)
{
NorthwindDataContext oDataContext = new NorthwindDataContext();
this._view.Products = from product in oDataContext.Products
where product.CategoryID == e.CategoryID
select product;
}
}
Here you can see the view is passed through the presenter using constructor injection. Now we subscribe the ListingCategory event of the view with presenter's OnCategoryListing method. Also we subscribe the ChangeCategory event of the view with thw presenter's OnCategoryChanged method.
Within these methods we call the LINQ classes to populate the data and set the data through view's property. That's it and we can test our whole application.
In the beginning, I said that MVP pattern really makes the unit testing easier. In context to this example, we don't need to write the aspx pages to test the application. We will write a mock class to test the application functionalities and later on we put the code in the aspx page.
Here is the code for mock class.
public class MockProductListing : IProductListing
{
IEnumerable<Category> _categories;
IEnumerable<Product> _products;
public void TestPageLoad()
{
EventHandler handler = this.ListingCategory;
if (handler != null)
{
handler(this, new EventArgs());
}
}
public void TestProductListingByCategory()
{
CategoryChangeEventHandler handler = this.ChangeCategory;
if (handler != null)
{
CategoryEventArgs oArgs = new CategoryEventArgs(Convert.ToInt16(1));
handler(this, oArgs);
}
}
#region IProductListing Members
public IEnumerable<Category> Categories
{
get { return this._categories; }
set { this._categories = value; }
}
public IEnumerable<Product> Products
{
get { return this._products; }
set { this._products = value; }
}
public event EventHandler ListingCategory;
public event CategoryChangeEventHandler ChangeCategory;
#endregion
}
In the mock class, we need to implement the view interface. We will test only two events; one is pageload; another is category dropdownlist selected index changed. You can see, I have written two test methods to test these two events.
Finally we will write the test mothods.
[TestMethod]
public void PageLoad()
{
List<Category> categories = new List<Category>();
MockProductListing _view = new MockProductListing();
ProductListingPresenter _presenter = new ProductListingPresenter(_view);
_view.TestPageLoad();
foreach (Category cat in _view.Categories)
{
categories.Add(cat);
}
Assert.AreEqual(8, categories.Count);
}
[TestMethod]
public void TestProductsByCategory()
{
List<Product> products = new List<Product>();
MockProductListing _view = new MockProductListing();
ProductListingPresenter _presenter = new ProductListingPresenter(_view);
_view.TestProductListingByCategory();
foreach (Product prod in _view.Products)
{
products.Add(prod);
}
Assert.AreEqual(12, products.Count);
}
Run the test methods and you will find the expected results.
So now, you can realize how MVP helps to test our application code. In original representation, we just need to copy the mock class's code to the aspx page.

Kalyan PPosted May 18, 2012, 9:12 AM
Hi, I am working on a small project with MVP implementation using Ajax, JQuery. I implemented passive view MVP pattern and all presenters are connected from view by event handling. The scenario is displaying a detail popup box from master list by clicking the link on master row. I have to make an ajax call to display the detail list. Now my question is how can I make a call via Ajax from client side to invoke an event. There are 2 scenarios in AJAX call that I know: 1. Call Page Method: In this, How can I call a page method (this is static by default) which internally invoke a event in presenter? If I call a presenter method directly in my view then It is violating the MVP pattern. 2. Call Web Service: How can I call a Web Service (Where it should be created?) how the presenter handle this service? I googled so many sites but I couldn't find a right answer to implement. Please clarify my questions and thanks for your support.
Mahesh ChandPosted Dec 8, 2010, 11:31 PM
Thank you for sharing Shubhendu.