Learning the Model View Presenter Pattern
I recently came across this article from Steve Eichert about how he dislikes the Windows forms designer. I can’t say that I think its evil, not like the web forms designer in VS 2003, and I actually think the WinForms designer in 2005 is pretty damn good. At the end of the article he linked to the Model-View-Presenter pattern on Martin Fowler’s site as an alternative to using the WinForms designer. I checked out the pattern having heard of it before but never using it. For some reason it took this time, and it seemed extremely useful because we’ve been thinking about ways to test our UI applications in a better way and by using the MVP pattern you can test much more of your application in an automated way.
On his site Fowler has a sample application that uses the MVP pattern written in java and he gives snippets of what the code would look like. I “ported” those snippets and recreated the sample application in VS 2005 as an exercise in how to use the MVP pattern for my WinForms applications. It was kind of hard starting out, as I wanted to create my form first, it took some deliberate thinking to force myself to unit test a stub of the form before actually creating it. You can download my version of the sample app here. Its built on VS 2005 and it references the NUnit 2.2.3 assemblies for the unit tests.
While I see the benefits of using the MVP pattern, I still am skeptical that it can completely test your application by using the stub views to run the test. I mean, there are still implementation details that you need to write inside the form’s code, and since you are testing the stub not the actual form, its certainly possible to have bugs in the form that won’t show up in your test. That being said, using the MVP pattern can certainly give you a much deeper test coverage that you get by just putting the code inside the form class, so there’s definitely a benefit to using the pattern.
jmiller said,
Wrote on November 18, 2005 @ 2:02 pm
Ben,
I’ve used the MVP paradigm on a couple of WinForms clients with very good results. You’re absolutely right that you can’t get away with only testing the presenters with mocks or stubs, but it makes the UI control logic vastly easier to unit test before you even try the integrated stack. You’ve always got to write multiple types and layers of tests, but unit testing the presenter logic will remove a lot of bugs quickly before you even attempt to debug through the full stack.
Even without using something like NUnitForms on the views you’ll get fewer bugs there because they’re thinner and much simpler. The “view” code itself is also easier to test because it doesn’t have quite so much coupling to the layers underneath it.
I like to start with just a mockup, code the presenter and flesh out the ISomethingView interface, then build the view last. I’ve routinely seen new screen features work on the very first try when you work this way.
Here’s another WinForms specific example of MVP –> http://codebetter.com/blogs/jeremy.miller/articles/129546.aspx
breichelt said,
Wrote on November 18, 2005 @ 2:42 pm
Jeremy, thanks for the comments. It was funny, when I googled for “model view presenter” your post was towards the top, and Scott Bellware had a post on the first page of results where he linked to a post by Jeffrey about the pattern, its a regular codebetter.com cyle!
But I do agree with you about the mvp pattern not being a cure all, but a great first defense about bugs, I’m going to try and incorporate it into my next project at work.
jmiller said,
Wrote on November 18, 2005 @ 2:56 pm
Incest comes to mind. I think I met Jeffrey for the first time right after his post.
jpalermo said,
Wrote on November 19, 2005 @ 1:11 pm
Here’s another good search to run:
http://www.google.com/search?hl=en&lr=&q=%22model+view+presenter%22+site%3Acodebetter.com
Anonymous said,
Wrote on November 21, 2005 @ 4:27 am
Hi,
MVP is a great pattern to test the UI logic and to make the separation of concerns when it comes to UI logic. I have used it very succesfully lately, on winforms, asp.net and even with net cf apps.
However, from time to time I do get the feeling of insecurity about the UI itself, as MVP is a pattern that makes testing the presenter/controller very easy, but the UI can remain completely untested.
For this reason I am thinking about ways to extend automated testing also to the UI. I believe that testing also the View is important for windows.forms apps as they are much more complex then web app views. If you also want to benefit from databinding (and sometimes you’re compelled to do it by some third party controls) then testing the view becomes more and more important.
So what do we do about this? One idea I had was to extend the view itself and make the mock. For instance, normally we could have:
public interface IView
{
void SetOrder(Order o);
Order GetOrder();
void DisplayMessage(string message);
}
public class Presenter
{
…
public void Init()
{
this.view.SetOrder(model.Order);
}
…
public void Save()
{
try
{
orderBusiness.Save(view.GetOrder());
view.DisplayMessage(”Order saved ok.”);
}
catch{
view.DisplayMessage(”Order could not be saved.”);
}
}
}
public class MockView:IView
{
private Order order = null;
private ArrayList messages = new ArrayList();
…
public void SetOrder(Order o)
{
this.order = order;
}
public Order GetOrder()
{
return this.order;
}
public void DisplayMessage(string message)
{
Console.WriteLine(message);
messages.Add(message);
}
}
Very easy to test. But if in the view I use databinding that means that the view needs to become visible.
public class OrderForm:Form,IView
{
…
public void SetOrder(Order o)
{
this.SuspendBindings();
this.RemoveBindings();
this.order = o;
this.DataBind();
this.ResumeBindings();
}
public Order GetOrder()
{
this.EndCurrentEdit();
return this.order;
}
public void DisplayMessage(string message)
{
MessageBox.Show(message,…);
}
…
private void DataBind()
{
this.txtNo.DataBindings.Add(”Text”,order,”No”);
this.txtDate.DataBindings.Add(”Text”,order,”Date”);
}
private void SuspendBindings()
{
this.BindingContext[order].SuspendBindings();
}
private void ResumeBindings()
{
this.BindingContext[order].ResumeBindings();
}
}
So could we have the MockView actually extend the OrderView itself, se that we could also have more control over testing the view also?
What do you think?
Sorry for the code, It was written on the spot;
breichelt said,
Wrote on November 22, 2005 @ 12:31 pm
Dan, I was thinking the same thing as I was learning about the MVP pattern. However, I dont think you can actually have a class that inherits from System.Windows.Forms.Form be hosted inside of nunit and have all of the events and databinding work correctly. Keep in mind that I’m no expert on WinForms, but I believe that it needs to be started as its own process for things to work correctly.
Anonymous said,
Wrote on November 23, 2005 @ 3:00 am
Hi,
After doing a little research I found out it is possible to extend the form itself to test with databinding, if needed. I will be publishing the source code on my blog soon.
Thanks,
Dan Bunea
http://danbunea.blogspot.com
breichelt said,
Wrote on November 23, 2005 @ 10:08 am
Dan, I would love to see this code, I’ll be watching your blog for it
Anonymous said,
Wrote on November 28, 2005 @ 3:05 am
Source code: Download
Lately, I have noticed that the Humble Dialog Box or Model…
Anonymous said,
Wrote on November 28, 2005 @ 8:29 am
Source code: Download
Lately, I have noticed that the Humble Dialog Box or Model…
Anonymous said,
Wrote on March 20, 2006 @ 10:49 am
This might be a bit late for you to be interested but; I’m currently looking at MVP/TDD for an internal teach in. The sample I drew up worked in a similar manner to your download. However I spotted a ‘bug’ in my own code and you appear to have the same issue.
public bool AlbumForm::IsClassical
{
get{ /* … */}
set
{
cbClassical.Checked = value;
txtComposer.Enabled = value;
}
}
this is asnippet from your production code where you actually have business logic. i.e. setting the classical checkbox state also enables the state of another control. (In my case is was the clearing of a list before populating it.)
My current thinking is that this is wrong and should be 2 properties/methods on the IAlbumView [ComposerEnabled *and* ISClassical] such that setting the current Album on the presenter should invoke both of these methods seperatly.
I’ve not had enough experience using MVP to ‘know’ if I’m right
so I’m still open minded about it all.
breichelt said,
Wrote on March 20, 2006 @ 10:54 am
Thats a good point adam, but IMO (not knowing much about MVP either) I would think that this is okay, because it still abstracts the concept of IsClassical from the actual view itself. The presenter simply tells the view that IsClassical is true/false then its up to the view to decide what actions to take because of that.
By adding a ComposerEnabled property, you are letting some implementation details of the view permeate into the presenter. Again, just my (possible naive) opinion
Anonymous said,
Wrote on March 20, 2006 @ 3:48 pm
> The presenter simply tells the view that IsClassical is true/false then its up to the view to decide what actions to take because of that.
I’ve thought more about this (and had a re-read of the martin fowler MVP page, which I’m sure has been updated since I last looked). The presenter implements *all* of the biz logic for any UI. The view is not allowed (my understanding of MVP) to “decide” any actions.
Now if I could the the product manager to use FitNess *and* I actually thought it was worth the effort we could have FIT tables to demonstrate what should happen in various UI senarios.
If only I’d gone to the effort of re-reading the Folwer page before my earlier post I could have better stated my thinking [now not then, which would have been then too had I read it, clear
].
Cheers,
adam
Anonymous said,
Wrote on March 30, 2006 @ 6:59 pm
Anonymous said,
Wrote on March 30, 2006 @ 7:04 pm
Latest Misunderstandings » Blog Archive » Initial Presenter-First demonstration program said,
Wrote on July 15, 2006 @ 8:53 pm
[…] My demo is going to try to extend slightly the demo album app used by Martin Fowler in describing Model-View-Presenter (MVP), I’ve also looked at a C# version of this app from Ben Reichelt’s blog. […]
James said,
Wrote on January 29, 2008 @ 12:10 pm
Ben, the link to the sample project does not work. Has it moved? If so, could you email me the project?
Setu said,
Wrote on March 6, 2008 @ 5:25 am
Hi Ben,
Yes, the link doesn’t work. Can you please email me the sample code as well or fix the link?
Thanks
Setu.