As mentioned in the introduction, I’m going to attempt to unit test my presentation model example application first. Of all the presentation patterns I’ve looked at, I’m expecting the presentation model to be the easiest to unit test.
By extracting view state and logic from the view, presentation model classes do not have any dependencies on view classes. They do sometimes have dependencies on each other, so test doubles may be required to isolate the functionality in one presentation model from functionality in another.
Unit testing AlbumForm
The AlbumForm class is quite straightforward to unit test as it only collaborates with the Album value object. I’ve decided not to create a test double for the Album VO because of its simplicity. It only has too methods, and I suspect they will be difficult to simulate without duplicating their behaviour.
In the unit test for AlbumForm I have created tests for all of the public methods of the AlbumForm class. Many of the public methods require more than one test in order to exercise every path of execution.
Unit testing AlbumBrowser
The AlbumBrowser class is a little harder to unit test because it collaborates with the AlbumForm class. In order to isolate my AlbumBrowser unit tests from the functionality of AlbumForm, I’ve decided to create a test double for the AlbumForm class. To do this I’ve made the following changes:
- Extracted an interface from AlbumForm – In order to create a test double for the AlbumForm, I’ve created an IAlbumForm interface which the AlbumForm now implements. The test double ‘StubAlbumForm’ also implementes IAlbumForm allowing it to be used as a substitute for AlbumForm.
- Modified AlbumBrowser to work with any IAlbumForm implementation - Now there’s more than one way to do this, and I’ve used a factory method. The AlbumBrowser is modified so that it creates its instance of AlbumForm in a factory method (that’s just an instance method that is reponsible for constructing the AlbumForm). The factory method is marked protected so that it can be overriden in a subclass. In my AlbumBrowser unit test I’ve created a private subclass of AlbumBrowser that overrides the factory method to return an instance of StubAlbumForm*. My unit test for AlbumBrowser tests an instance of the private sub-class rather than AlbumBrowser itself. This allows me to test AlbumBrowser functionality in isolation of the AlbumForm class.
- Added a property to StubAlbumForm to allow me to control the flow of tests – The AlbumBrowser takes different actions depending on the result from the ‘changesToSave’ method on the AlbumForm class. In order to test these different paths I’ve added a ‘pendingChanges’ property to the StubAlbumForm that allows me to specify the return value of the ‘changesToSave’ method.
I’ve also captured these modifications in the form of a UML diagram, so take a look if none of the above makes any sense.
Together, these changes allow me to test AlbumBrowser in isolation of the AlbumForm class. Doing all of this may be considered overkill for such a small application, but it becomes important for larger applications with deeper hierarchies of presentation model instances and more complex collaborations.
Unit testing Album
The Album VO doesn’t collaborate with any other objects, so testing it is very easy. The unit test for the Album class covers the two public methods: clone() and equals().
Unit testing AlbumDelegate
Since this class is a fake delegate, I’m not going to test it. In real applications it will be necessary to create test doubles for delegates.
The presentation model’s independence from the view simplifies the unit testing of application-specific user interface logic. The main challenge is isolating the functionality of one presentation model from that of another. I’ve chosen to use a factory method approach in my application, but other creational patterns could also be applied, as could some form of dependency injection.
The presentation model classes in this application are still not very well encapsulated. Many of the properties the view binds to are public properties; this simplifies binding, but undermines encapsulation. I’d like to tighten up the encapsulation on these classes, but that’s a task for another day.
*A similar approach in Java would be to use Anonymous Inner Classes inside tests or fixtures to create test-specific sub-classes (here’s an example from IBM). EcmaScript and consequently ActionScript do not support this language feature, so I’ve used a private class instead.