January 2007 - Posts
Source code:
DownloadLately, I have noticed that the Humble Dialog Box or Model View Presenter are gaining more and more acceptance among software developers, especially in agile communities, because of its benefits regarding the very good separation between the view and the behavior and because it can be very easily unit tested, on a problematic field: user interface.
Let's meet Model View PresenterIn model view presenter just as
Martin Fowler or
Michael Feathers [2] say, the logic of the UI is separated into a class called presenter, that handles all the input from the user and that tells the "dumb" view what and when to display. The special testability of the pattern comes from the fact that the entire view can be replaced with a mock object and in this way the presenter, which is the most important part, can be easily unit tested in isolation. Let's take a small sample:
A client writes in a user story:
User management
The system will support managing users. Each user can have a username and a password. The system will present a list of user and when one is selected, it can be edited. Also there will be functionality to add new users and to be able to select a user from the list and delete it.Ok, now let's get to work:
Our view should need the following data, which will be put into an interface:

The UsersList represents the list of users, and the User is the current user selected at a certain time.
When the UI is displayed, we want to be able to see the list of available users, and by default the first in the list to be selected. Let’s write a small test for that. Having no view, we will make a simple implementation of the IUsersView, called UsersMockView. Using it we will be able to see if the presenter when it is initialized sets the needed list and the first is selected in it.

where we have:

And for the data we use a separate model class, like:

If I want to make my test compile, I must write my presenter, see the test failing then keep working on it until the test is working:

and now it is time for a new test, and a small refactoring in the test code:

Now we can go further and add the missing code ... until it works. We then follow the same procedure until we have quite a suite that test selecting a user in the list, updating its details, deleting a user, deleting all the users, and others. Now we know we have a Presenter that works fine. At least where it is tested.
Could we have used a dynamic mock?I like writing in some cases the mock objects by hand. However there are a few dynamic solutions that can prove quite helpful, like NMock [3] for instance. NMock can create mock objects, using Reflection.Emit and your interfaces “on the fly”. Then it is also very useful when it comes to seeing what methods were invoked in the mock object by your class under test. You can also set predefined responses, when the class under test invokes your mock object, but that is another matter. Let’s make a small sample, just as we did before manually. For the TestInit, using NMock it will be like:

It works. The presenter has invoked the properties of the mock object, once as expected and set the expected values. This way we can throw away our previous tests, and can build a new presenter based on testing with dynamic mock objects.
Implementing the real viewIf you read Michael Feather’s “
Humble Dialog Box” article, you’ll be able to see very well how the real view should be built. The presenter sets the values into the view which are the propagated to the properties of the controls, much like:

but once .NET was released, it comes with the concept of data binding, and there are some developers that do not want to ignore it and use the “old and safe” ways as above.
How does MVP cope with data-binding?.NET 2.0 comes with a new and much better concept for data binding then 1.0 or 1.1 did, the BindingSource. This now has the possibility to be connected to different kinds of data sources, including business objects. For our interface we create two: bsUser for User and bsUserList for the list of Users. Then for binding we can use, the designer as:

Now, we go back to our properties that are used by the presenter to “push” data into the view to be displays, and modify the code to use the binding sources as follows:

As you can also see, user actions on the view are delegated to the presenter, which is now fully in control of what behavior of out user management interface.
If we run the tests again, they are all green, all succeed. This is great, but this green is false if you think that it works with data-binding because the tests do not touch in any way the actual view. So what do we do?
A first option would be to leave it like that. But since a view for a desktop application is not exactly as “dumb” as we would like, and can quickly become a source of error, we need to add some tests.
Using a functional testing framework like NUnitForms or SharpRobo could be a solution but this can result in tests that test the same thing, and that is not exactly maintenance friendly. But wait, what if our stub is not exactly a stub but an extension of the view itself, to which we can add testing code. For this we inherit, the real view and create ExtendedUsersView. Now we want to modify the testing code in such a way, that the existing code is still reused. For this we inherit the manual test we have written, and just override the SetUp method:

If we run it, it will run the initial tests but on the actual view. It needs to be shown as data-binding to the controls is done when the controls become visible, but that is not a problem. The problem can be speed, but if you run the code you’ll be able to see that the difference is not that significant. If speed is a problem, then maybe you can run the tests that use the actual view, more rarely, as you can get quite enough feedback from the mock tests.
The processAbout the process of building destop application pieces, the way I have constructed the application above, might seem wrong, as using TDD, I built the presenter, but I did not have the view yet, and that was constructed later on the exact same set of tests. In practice I wouldn't recommend this, as the first step, building the presenter without the view, using TDD might lead to a code that will need big refactorings (both presenter and tests) when the view is built. A better approach would be to construct, a two test cases, one inheriting teh other, with two setup methods, one with the mock view, and one with the actual extended view, then build a test inside the first, and build some code on it in both the presenter and the view, then add a new test and so on, until we have tested both the presenter and the view, having both tests that are fast and isolate the presenter's bahavoius and tests that also cover the view.
ConclusionI have tried to present a solution, that can cover more of the code with unit tests, then only the presenter, as for desktop applications this can be an important issue. I have also tried to find a solution that works with data-binding, and what I have found seems ok so far, but only time and more research and tests can really tell if this was a good choise….
1. Martin Fowler - Model View Presenter2. Michel Feathers - The humble dialog box3. Peter Provost - TDD in .NET4. Jeremy Miller - A simple example of "humble dialog box"5. Ben Reichelt - Learning teh model view presenter pattern
Download Sources, and view demosGoalLet's say we need to write an application very fast, that can do the basic CRUD operations for a Product. Ruby on rails (
www.rubyonrails.org) came up with the excellent idea of scaffolding, and the idea was ported into the Castle Monorail project (
www.castleproject.org). However, the default generator both in ROR and in MR, do not generate ajax based code. For ROR the solution is at:
www.ajaxscaffold.com but nothing so far for MR. So I decided to take matters in my own hands...
Where do we start from?The excellent generator by
Marc Andre Cournoyer can generate projects, controllers, migrations, model etc and the templates can be changed to suit one's needs extremely easy. Starting from Marc Andre's generator I configured the templates to generate AJAX based code.
Let's see how it works, step by step starting from nothing.
Step 1: we make a new MonoRail projectUsing latest RC2, and VS.NET 2005, we generate the project using the wizard inside VS.NET.
resulting in:

Then we edit the web.config and we create a new database called Products.
Step 2: we generate the persistent activerecord class and the database tableStarting for a basic Castle Monorail/ActiveRecord project, we start by creating the Product class, and then generating the database table corresponding to it. In the application's root folder, we type: generate model Product Name Description Price and it generates the code for us:

obtaining the following code (click view all files on the web project, and include the new file in project)
///
/// An instance of this class represents a Product.
///
[ActiveRecord]
public class Product : ActiveRecordValidationBase {
#region Fields
private int _id;
private string _name;
private string _description;
private string _price;
#endregion
#region Persistent properties
[PrimaryKey]
public int Id {
get { return _id; }
set { _id = value; }
}
[Property]
public string Name {
get { return _name; }
set { _name = value; }
}
[Property]
public string Description {
get { return _description; }
set { _description = value; }
}
[Property]
public string Price
{
get { return _price; }
set { _price = value; }
}
#endregion
internal static IList FindAll()
{
return FindAll(typeof(Product));
}
internal static Product Find(int id)
{
return FindByPrimaryKey(typeof(Product), id) as Product;
}
}
To generate the database schema we just use:
ActiveRecordStarter.CreateSchema();
and we have the table in our database.
Step 3: we generate the Ajax Scaffolding codeWe type in our command window: generate scaffold Product and it will generate all the needed code dor adding, listing, editing and deleting products, using Ajax:

now we include the generated files in our solution from Visual Studio 2005 (right click, Include in project):
Step 4: we run the code. It works!
We start the application:

then we add:

after adding two products:

now viewing in place:

and editing:

and the same with deleting.
What about validations?Let's say that the name and the price are required. We modify the Product class, to add the validation attributes:
///
/// An instance of this class represents a Product.
///
[ActiveRecord]
public class Product : ActiveRecordValidationBase {
#region Fields
private int _id;
private string _name;
private string _description;
private string _price;
#endregion
#region Persistent properties
[PrimaryKey]
public int Id {
get { return _id; }
set { _id = value; }
}
[Property
,ValidateNotEmpty("Name is not optional.")]
public string Name {
get { return _name; }
set { _name = value; }
}
[Property]
public string Description {
get { return _description; }
set { _description = value; }
}
[Property
, ValidateNotEmpty("Price is not optional.")]
public string Price
{
get { return _price; }
set { _price = value; }
}
#endregion
internal static IList FindAll()
{
return FindAll(typeof(Product));
}
internal static Product Find(int id)
{
return FindByPrimaryKey(typeof(Product), id) as Product;
}
}
and restart the application:
How hard is it to extend the product?Let's say that we've just found out that besides the Name, Description and Price, we also need to add to each product a serial number. We modify the Product class, adding the new field and property:
private string _serialNumber;
...
[Property]
public string SerialNumber
{
get { return _serialNumber; }
set { _serialNumber = value; }
}
Now, we recreate the table:
ActiveRecordStarter.CreateSchema();
and start the application:

and

so it doesn't need any modification in the code or views.
What about relationships?Let's consider that we want each product to be part of a Category. Following the steps above we create a class Category:
[ActiveRecord]
public class Category : ActiveRecordValidationBase {
#region Fields
private int _id;
private string _name;
private IList products = new ArrayList();
#endregion
#region Persistent properties
[PrimaryKey]
public int Id {
get { return _id; }
set { _id = value; }
}
[Property]
public string Name {
get { return _name; }
set { _name = value; }
}
[HasMany(typeof(Product))]
public IList Products
{
get { return products; }
set { products = value; }
}
#endregion
public override string ToString()
{
return this.Name;
}
and modify the product to be part of a Category by adding:
private Category _category=null;
...
[BelongsTo("CategoryID")]
public Category Category
{
get { return _category; }
set { _category = value; }
}
we regenerate the database, obtaining:

Using the generator we also generate the ajax scaffolding code to add/edit/delete and list categories. Now we add two categories:

and going to add new products we'll also have the category combobox, without us making any modification in the code or the views:
Conclusion
As it can be seen above, with very little effort, in 10 minutes we can create an easy to extend ajax application (thanks to Castle Project and Marc Andre's generator). The code is quite clear and easy to debug and extend, and since it is ajax based it can be easily integrated in existing web applications.
Download the VS 2005 addinIn my previous article, I explained how by modifying Marc Andre Cournoyer's generator, we made it generate Ajax based, scaffolding code for Castle MonoRail. In the meantime, my colleague Gabi Munteanu, managed to put together a Visual Studio 2005 addin, exactly for this purpose.
1. Generate the modelLet's start from an generated ActiveRecord class called Project we had the last time, generating the ajax scaffolding code needed for the project:
obtaining:
using Castle.ActiveRecord;namespace Models{ /// /// An instance of this class represents a Project. /// [ActiveRecord] public class Project : ActiveRecordValidationBase { #region Fields private int _id; private string _name; private string _description; #endregion #region Persistent properties [PrimaryKey] public int Id { get { return _id; } set { _id = value; } } [Property] public string Name { get { return _name; } set { _name = value; } } [Property] public string Description { get { return _description; } set { _description = value; } } #endregion }}Using the ActiveRecordStarter.CreateSchema we also create the corresponding database table.
2. Generate the scaffoldthen
Unfortunetely, we'll still have to manually include the files in the project (still working on this):
3. Final adjustmentsIn order to make it work we need some adjustments to our Project class:
using System.Collections;using Castle.ActiveRecord;using NHibernate.Expression;namespace Models{ /// /// An instance of this class represents a Project. /// [ActiveRecord] public class Project : ActiveRecordValidationBase { #region Fields private int _id; private string _name; private string _description; #endregion internal static IList FindAll() { return FindAll(typeof(Project)); } internal static IList FindAll(string property) { return property.Equals("") ? FindAll(typeof(Project), new Order[1] { Order.Desc("Id") }) : FindAll(typeof(Project), new Order[1] { Order.Asc(property) }); } internal static Project Find(int id) { return FindByPrimaryKey(typeof(Project), id) as Project; } #region Persistent properties [PrimaryKey] public int Id { get { return _id; } set { _id = value; } } [Property] public string Name { get { return _name; } set { _name = value; } } [Property] public string Description { get { return _description; } set { _description = value; } } #endregion }}Now we see the result:Conclusion
The project is till in early stages, but it can still generate very good code and save a lot of time needed to generate the same all CRUD code, needed in any application.
A few weeks ago on the TestDrivenDevelopment mailing list, Ron Jeffies, one of the XP gurus stated that "in order to obtain good code, writing tests and code is faster then just code". To find out if this is true or not let's make a small experiment.
The mini TDD experiment We assume that we are programmers and we need to code a function that divides two positive numbers. For this experiment we will compare the traditional and the TDD approaches.
Approach #1. Code and fix As programmers, for a simple division we will write the following “pseudo” code:
Function Divide(No1, No2)
Return No1/No2 For this very simple method, let’s assume we needed 5 seconds to write it. Now let’s test if it works. First we try 6 and 2, expecting 3. It works. Let’s try another combination: 1 and 2, expecting 0.5. It works. Now let’s try 8 and 0. An error just occurred. This means we need to modify the program to display a message to the user that the second number cannot be 0:
Function Divide(No1,No2)
If No2 = 0 then display message “Division by 0 cannot be performed”
Else Return No1/No2 Now let’s test our function again. 6 and 2, result 3, good, 1 and 2, 0.5 as expected, 8 and 0 and a message “Division by 0 cannot be performed” occurs as expected. Now, our program works fine.
Assuming that manual testing is slow and for each combination of numbers we need about 10 seconds, this means that a testing session takes 30 seconds. The total time in which we developed the code was: 5 seconds to write the function, 30 seconds to test and see it has problems with division by 0, then about another 5 to correct the function and 30 minutes to test it again and make sure it works: total 5+30+5+30=70 seconds, a minute and 10 seconds.
Approach #2: Test Driven development In test driven development, there are a series of steps to write a piece of code, starting with and automated test written first and ending up making that test succeed, by writing the code that it tests. Let’s see how it goes:
Function TestNormalDivision()
Expect 3 as a result of Divide(6,2) The code above compares the value expected and the value returned by our (yet unwritten code) and if they do not match it fails.
One very important step now is to make sure our test really tests something and it does not work every time, no matter what the code under test does. So for this we need to make sure that when it needs to fail, it fails. So we write the following function:
Function Divide(No1, No2)
Return 0 Now we run the test, and it fails saying: expected 3 but the result was 0. So now we modify the function to return pass the test.
Function Divide(No1, No2)
Return 3 Now we run the test again: 1 test succeeded. Excellent. Now let’s see if it works for 1 and 2, so we update the test:
Function TestNormalDivision()
Expect 3 as a result of Divide(6,2)
Expect 0.5 as a result of Divide(1,2) We run the test. Failure. Oooh, we just realize the mistake we made (code always returns 3) and modify the Divide function:
Function Divide(No1, No2)
Return No1/No2Running the test, now passes all our expectations. But now we think, what would happen if we used 8 and 0. Let’s add a new test to the test suite (now we have two) and make sure that if there is division by 0, the user is notified:
Function TestDivisionByZero()
Expect message “Division by 0 cannot be performed” displayed as a result of Divide(8,0) We run the test. It fails. Now we modify our function to make it work:
Function Divide(No1,No2)
If No2 = 0 then display message “Division by 0 cannot be performed”
Else Return No1/No2 Running all our tests, we discover that they all succeed.
How much time did we need to write this code? We needed 5 seconds to write the first test, 5 seconds to make sure it fails, 1 second to run the test (now testing is done by the computer so we assume it should be at least 10 times faster then manual testing), 5 seconds to modify the code to make the test work, 1 second to run the test, another 5 seconds to extend the test to verify the 1,2 combination, 1 second to see that the test fails, 5 seconds to modify the function and 1 second to see it working, another 5 seconds to write the second test and 2 seconds to see the first test work but the second failing, and 5 seconds to complete the code and another two to run the 2 tests and make sure it works. Wow, a long way: 5+5+1+5+1+5+1+5+1+5+2+5+2 = 42 seconds.
Using both approaches, we ended up with the same code. The amount of code written for the second approach is bigger then for the first, having the code and the tests. The amount of time needed for the second approach was arguably smaller then the amount for the first approach, which leads us to Ron Jeffries’s conclusion: to obtain good code, writing tests and code is faster then code alone. The main advantage is that we use computer power to do the testing rather then human power, so we are much faster. Then we can run the automated tests over and over again and it will take 2 seconds to see if they work, manually it will take 30 to do the same thing.
Let’s go further with our experiment, assuming that now we need to extend the program to be able also to do addictions, subtractions and multiplications.
Approach #1. Code&FixSince all these operation are not affected by 0, but we test that anyway, the code written first will work, so it would take about 5 seconds to write each method, and testing each with 3 combinations of numbers would result in about 30 seconds to test each. The amount of time, needed would be 5+30+5+30+5+30 = 105 seconds, 1 minute and 45 seconds. Testing the whole program (the 3 new methods and the division method) would take us 4*30 = 120 seconds, which is 2 minutes.
Approach #2. TDD Operations just as above will need only one test, checking 3 combinations. Let’s say it takes 10 seconds to write a test method like this:
Function TestMultiplication()
Expect 0 as a result of Multiply(6,0)
Expect 3 as a result of Multiply(3,1)
Expect -9 as a result of Multiply(3,-3) Then we’d have to make sure it fails: 5 seconds, 1 second to run the test, then we’d write the code to make it work: 5 seconds and 1 second to make sure it works, so it takes about 10+5+1+5+1 = 22 seconds for each new function, resulting in 3*22 = 66 seconds or 1 minute and 6 seconds to write the new functions. Testing all the code would mean running 5 test methods (2 for division and 1 for the other three), which would be run in 5 seconds.
Tests and code, faster then just code Comparing the times needed to test our incredibly simple system: 2 minutes vs. 5 seconds show us that not only the code is written faster (110+105=215 seconds vs 66+45=111 seconds), but making sure it works requires far less time for the TDD approach. And second big advantage, it can be done by a computer.
Using a continuous integration machine that downloads the program sources and runs the test suite, then sends us an email telling us what happened, means 5 seconds for the machine and 0 seconds on my side to test the whole system. Using the first approach, would take me 2 minutes to make sure the whole system works. I could delegate this responsibility of testing the whole system to the testing team, but the feedback times, telling me whether the system works as a whole or not, increase rapidly to days and weeks and by that time I should be doing something else.
Scalability In the 3rd phase of our little experiment, we analyze what would happen if our system would have 400 functions instead of 4. Using the first approach it would need about 12000 seconds (that is over 3 hours) for a full test, while using the TDD and automated testing suite about 500 seconds or, better said, less then 10 minutes. This simple sample shows us scalability when it comes to TDD vs traditional coding approaches. The testing team could work, to some extent in parallel, but after, all I could set my integration machine to divide the tests and work in parallel.
After making this very small experiment, we showed how test driven development is, compared with just coding:
o faster to develop
o faster to test the whole system and give feedback
o scalable Tests as documentation Another advantage of the method described above is that, the automated tests can act as a very good documentation of the code written. In traditional approaches, just documenting things that can be very easily deduced from the automated tests, like how a function works, would increase even more the development time. After all, just reading:
Function TestDivisionByZero()
Expect message “Division by 0 cannot be performed” displayed as a result of Divide(8,0) tells me or someone new in the project, that if you try to perform a division by 0, the system will display an error message on the screen.
Embrace change: how? Having a system with 4, 400, 1000…100.000 methods, doesn’t really comfort me when it comes to making a change in it. If I change one tiny piece of code somewhere, could I break something in another part of the system? And if I do, how could I know fast enough, to be able to either correct it or reverse my changes?
To have the feedback from the code, telling me if and where I’ve broken some existing functionality, I would normally need to retest the whole system. For a 4 methods system, it would take 2 minutes, but for a more likely system, it might take hours, days or even weeks. So the courage to change decreases with the system getting bigger, thus is shortening the life of the system. When a system is too rigid and can no longer adapt to the changes on the market, it is bound to die.
Having a full regression automated test suite, that runs very fast and can be run very often, means fast feedback. Fast feedback means changes are less risky and can be done easier and faster, thus extending the life of a system.
Design advantages Another advantage of writing automated tests for the code is that the code written tends to be very loosely coupled, thus better designed. Test driven development also tends to eliminate “partially completed code”, encouraging less code to be written, as the programmer is more focused on what is really needed, thus decreasing the amount of code and its complexity.
At a macro level, the fact that changes, even in the architecture are much easier to be performed, when using TDD combined with aggressive refactoring, allows the programmers to continuously upgrade the design and update the architecture. Since the changes are easy to do, the evolutionary design technique is encouraged, having a much smaller need to build a flexible architecture upfront, following the YAGNI principle from XP.