You can TDD user interface heavy applications if you seperate the logic out of the user interface. This is MVC in a nutshell. Here is one conceptual way of doing it expressed as class-diagram (with the model omitted):
+----------------------+ 1
| MyDownloadUI +--------------+
+----------+-----------+ |
| |
| implements |
v |
+----------------------+ | 1
| {interface} |1 1+--------+------------+
| DownloadView +-----+ DownloadController |
+----------------------+ +---------------------+
The only thing you need to do on the user interface is to implement a DownloadView
interface and have a reference to DownloadController
on where it should send it's actions to. The DownloadController should only have a reference to the DownloadView interface whenever it needs to manipulate the UI (more specifically the view). The constructors should look something like these:
//Sample of MyDownloadUI
DownloadController controller;
public MyDownloadUI {
this.controller = new DownloadController(this);
//...
}
//Sample of DownloadController
DownloadView view;
public DownloadController(DownloadView view) {
this.view = view;
//...
}
This way, the UI can be changed without the controller to worry about how the view looks or what the names of all the labels and lists are.
This has the benefit that you can TDD the logic in the download controller and have a mock that replaces the UI.
To test the actual UI you don't really do unit tests per se, it'll be more a functional test because MyDownloadUI is tightly coupled with DownloadController (unless you make an interface for the DownloadController). For a small project like this, you can pretty much just do manual smoke testing whenever you change the UI or wire something new to the controller.
Whenever you feel like a class is starting to get too much, you always have the option of breaking the logic out to another class (which makes TDD a lot easier). You've already given examples, e.g. DownloadTask
, which is clearly a model class, so it's a good start. Then you have the FileDownloader
which sends a DownloadedFile
to a FileWriter
.
The easiest implementation of DownloadController
that I could think of is just one method:
goDownload(List<string> urls)
that the MyDownloadUI calls when it wants to start downloading
Another one would be:
addUrl(string url)
adds an url to the downloadcontroller's internal list
clearUrls()
removes all urls in the internal list
goDownload()
which takes the list of urls and starts the "download process"
There are a lot of TDD tutorials out there, my favorite is the video on dnrTV with Jean Paul Boodhoo (Part 1, Part 2). There is a lot to take in, but it shows a lot how to do it in practice.