I am trying to apply TDD for the first time with a Form for an existing WinForms application that I need to write. I read "Agile Principles, Patterns, and Practices in C#", which is where most of my knowledge of TDD came from.
In the book the author recommends doing UI development with a slightly modified form of MVP which he referred to as Supervising Presenter which has the Presenter having a dependency on the View and the Model. I like the way this has caused the code in the Presenter to look. For the sake of illustration here is a trivial example:
class Presenter
{
Public IDomainApi _api;
Public IView _view;
...
public void PerformOperation()
{
bool userDecidesToPerformOperation = _view.PromptUserToConfirmOperation();
if( userDecidesToPerformOperation )
{
bool success = _api.PerformOperation();
if( success)
_view.AlertUserOperationSuccessful();
else
_view.AlertUserOperationFailed();
}
}
}
This all works great, for testing purposes I have a mock IDomainApi
and a mock IView
, I was able to be sure that my logic is sound in the controller life is good.
For the actual application _api
is the real implementation of IDomainApi
which does work over a network, and _view
is an instance of a Form
that implements IView
which has all the required controls.
Some of the operations that the real IDomainApi
performs take some time so I decided to modify the Presenter method slightly to alert the user that stuff is going on. The presenter was modified like so:
public void PerformOperation()
{
bool userDecidesToPerformOperation = _view.PromptUserToConfirmOperation();
if( userDecidesToPerformOperation )
{
_view.NotifyPendingOperation("Performing operation ...");
bool success = _api.PerformOperation();
_view.PendingOperationCompleted();
if( success)
_view.AlertUserOperationSuccessful();
else
_view.AlertUserOperationFailed();
}
}
I added the new methods to the "real" IView
implementation, and it just displays a simple dialog box that contains the passed in text and a progress bar set to indicate activity (marqee setting). Sadly when testing I found that the dialog does not have the progress indicator active because the thread the Presenter
is running in is the UI thread (and its blocked waiting for _api.PerformOperation()
to complete).
I have tried modifying the code that creates and uses the Presenter
to call Presenter
in a separate thread, but that causes the UI to not render properly (rendering only happens on UI thread and not the new one). The only solutions I can see to this problem involve expanding IView
to expose the UI thread so that I can invoke the appropriate IView
methods on that thread, but this seems like it would make the Presenter code ugly and would make it dependent on WinForms. Has anybody found a better way to handle this sort of thing? My searches online so far tend to produce mostly information about TDD with Web, does anybody know of a good resource on how to do some of these things that are specific to WinForms?